Skip to content

Commit fda5d89

Browse files
authored
Merge pull request #3817 from yue9944882/refactor/merge-token-file-auth
Refactor: Merge TokenFile auth with refresh auth
2 parents b0a7e52 + 80d68d1 commit fda5d89

File tree

4 files changed

+52
-67
lines changed

4 files changed

+52
-67
lines changed

util/src/main/java/io/kubernetes/client/util/credentials/RefreshAuthentication.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.time.Instant;
2121
import java.util.function.Supplier;
2222

23+
import io.kubernetes.client.util.exception.TokenAquisitionException;
2324
import okhttp3.Interceptor;
2425
import okhttp3.OkHttpClient;
2526
import okhttp3.Request;
@@ -28,7 +29,6 @@
2829
// TODO: prefer OpenAPI backed Auentication once it is available. see details in
2930
// https://github.com/OpenAPITools/openapi-generator/pull/6036. currently, the
3031
// workaround is to hijack the http request.
31-
// TODO: Merge this with TokenFileAuthentication.
3232
public class RefreshAuthentication implements Authentication, Interceptor {
3333
private Instant expiry;
3434
private Duration refreshPeriod;
@@ -43,14 +43,22 @@ public RefreshAuthentication(Supplier<String> tokenSupplier, Duration refreshPer
4343
public RefreshAuthentication(Supplier<String> tokenSupplier, Duration refreshPeriod, Clock clock) {
4444
this.expiry = Instant.MIN;
4545
this.refreshPeriod = refreshPeriod;
46-
this.token = tokenSupplier.get();
46+
try {
47+
this.token = tokenSupplier.get();
48+
} catch (RuntimeException e) {
49+
throw new TokenAquisitionException(e);
50+
}
4751
this.tokenSupplier = tokenSupplier;
4852
this.clock = clock;
4953
}
5054

5155
private String getToken() {
5256
if (Instant.now(this.clock).isAfter(this.expiry)) {
53-
this.token = tokenSupplier.get();
57+
try {
58+
this.token = tokenSupplier.get();
59+
} catch (RuntimeException e) {
60+
throw new TokenAquisitionException(e);
61+
}
5462
expiry = Instant.now(this.clock).plusSeconds(refreshPeriod.toSeconds());
5563
}
5664
return this.token;

util/src/main/java/io/kubernetes/client/util/credentials/TokenFileAuthentication.java

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,63 +12,32 @@
1212
*/
1313
package io.kubernetes.client.util.credentials;
1414

15-
import io.kubernetes.client.openapi.ApiClient;
1615
import java.io.IOException;
1716
import java.nio.charset.Charset;
1817
import java.nio.file.Files;
1918
import java.nio.file.Paths;
20-
import java.time.Instant;
21-
import okhttp3.Interceptor;
22-
import okhttp3.OkHttpClient;
23-
import okhttp3.Request;
24-
import okhttp3.Response;
19+
import java.time.Duration;
2520

2621
// TODO: prefer OpenAPI backed Auentication once it is available. see details in
2722
// https://github.com/OpenAPITools/openapi-generator/pull/6036. currently, the
2823
// workaround is to hijack the http request.
29-
public class TokenFileAuthentication implements Authentication, Interceptor {
30-
private String file;
31-
private String token;
32-
private Instant expiry;
33-
24+
public class TokenFileAuthentication extends RefreshAuthentication {
3425
public TokenFileAuthentication(String file) {
35-
this.expiry = Instant.MIN;
36-
this.file = file;
37-
}
38-
39-
private String getToken() {
40-
if (Instant.now().isAfter(this.expiry)) {
41-
try {
42-
this.token =
43-
new String(Files.readAllBytes(Paths.get(this.file)), Charset.defaultCharset()).trim();
44-
expiry = Instant.now().plusSeconds(60);
45-
} catch (IOException ie) {
46-
throw new RuntimeException("Cannot read file: " + this.file);
47-
}
48-
}
49-
50-
return this.token;
26+
this(file, Duration.ofMinutes(1));
5127
}
5228

53-
public void setExpiry(Instant expiry) {
54-
this.expiry = expiry;
29+
public TokenFileAuthentication(String file, Duration refreshPeriod) {
30+
super(() -> {
31+
return getToken(file);
32+
}, refreshPeriod);
5533
}
5634

57-
public void setFile(String file) {
58-
this.file = file;
59-
}
60-
61-
@Override
62-
public void provide(ApiClient client) {
63-
OkHttpClient withInterceptor = client.getHttpClient().newBuilder().addInterceptor(this).build();
64-
client.setHttpClient(withInterceptor);
35+
private static String getToken(String file) {
36+
try {
37+
return new String(Files.readAllBytes(Paths.get(file)), Charset.defaultCharset()).trim();
38+
} catch (IOException e) {
39+
throw new RuntimeException("Cannot read file: " + file);
40+
}
6541
}
6642

67-
@Override
68-
public Response intercept(Interceptor.Chain chain) throws IOException {
69-
Request request = chain.request();
70-
Request newRequest;
71-
newRequest = request.newBuilder().header("Authorization", "Bearer " + getToken()).build();
72-
return chain.proceed(newRequest);
73-
}
7443
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
package io.kubernetes.client.util.exception;
14+
15+
public class TokenAquisitionException extends RuntimeException {
16+
public TokenAquisitionException(Exception exception) {
17+
super(exception);
18+
}
19+
}

util/src/test/java/io/kubernetes/client/util/credentials/TokenFileAuthenticationTest.java

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,19 @@ class TokenFileAuthenticationTest {
4242
static WireMockExtension apiServer =
4343
WireMockExtension.newInstance().options(options().dynamicPort()).build();
4444

45+
private ApiClient apiClient;
46+
4547
@BeforeEach
4648
void setup() {
47-
final ApiClient client = new ApiClient();
48-
client.setBasePath("http://localhost:" + apiServer.getPort());
49-
this.auth = new TokenFileAuthentication(SERVICEACCOUNT_TOKEN1_PATH);
50-
this.auth.provide(client);
51-
Configuration.setDefaultApiClient(client);
49+
this.apiClient = new ApiClient();
50+
this.apiClient.setBasePath("http://localhost:" + apiServer.getPort());
51+
Configuration.setDefaultApiClient(this.apiClient);
5252
}
5353

5454
@Test
55-
void tokenProvided() throws ApiException {
55+
void tokenProvidedTokenNormalFileReadShouldWork() throws ApiException {
56+
Authentication authn = new TokenFileAuthentication(SERVICEACCOUNT_TOKEN1_PATH);
57+
authn.provide(this.apiClient);
5658
apiServer.stubFor(
5759
get(urlPathEqualTo("/api/v1/pods")).willReturn(okForContentType("application/json",
5860
"{\"items\":[]}")));
@@ -63,19 +65,6 @@ void tokenProvided() throws ApiException {
6365
1,
6466
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
6567
.withHeader("Authorization", equalTo("Bearer token1")));
66-
67-
this.auth.setFile(SERVICEACCOUNT_TOKEN2_PATH);
68-
api.listPodForAllNamespaces().execute();
69-
apiServer.verify(
70-
2,
71-
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
72-
.withHeader("Authorization", equalTo("Bearer token1")));
73-
74-
this.auth.setExpiry(Instant.now().minusSeconds(1));
75-
api.listPodForAllNamespaces().execute();
76-
apiServer.verify(
77-
1,
78-
getRequestedFor(urlPathEqualTo("/api/v1/pods"))
79-
.withHeader("Authorization", equalTo("Bearer token2")));
8068
}
69+
8170
}

0 commit comments

Comments
 (0)