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 c7bdf399662..ed42c383c1b 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 @@ -395,6 +395,7 @@ public Config(String masterUrl, String apiVersion, String namespace, boolean tru this.masterUrl = ensureEndsWithSlash(ensureHttps(masterUrl, this)); this.maxConcurrentRequests = maxConcurrentRequests; this.maxConcurrentRequestsPerHost = maxConcurrentRequestsPerHost; + this.autoOAuthToken = autoOAuthToken; } public static void configFromSysPropsOrEnvVars(Config config) { @@ -966,19 +967,9 @@ public static String getKeyAlgorithm(String clientKeyFile, String clientKeyData) return null; } - public String getUserConfiguredOauthToken() { - return oauthToken; - } - @JsonProperty("oauthToken") public String getOauthToken() { - if (this.oauthTokenProvider != null) { - return this.oauthTokenProvider.getToken(); - } - if (this.oauthToken != null) { - return oauthToken; - } - return autoOAuthToken; + return oauthToken; } public void setOauthToken(String oauthToken) { diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptor.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptor.java index 14c243da2b3..b7341803cc9 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptor.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptor.java @@ -26,6 +26,7 @@ import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; /** * Interceptor for handling kube authentication. It will either be basic auth, or token based. This class takes responsibility @@ -37,34 +38,58 @@ public class TokenRefreshInterceptor implements Interceptor { public static final String NAME = "TOKEN"; - private final Config config; - private HttpClient.Factory factory; + protected final Config config; + private final Function> remoteRefresh; private static final int REFRESH_INTERVAL_MINUTE = 1; - private Instant latestRefreshTimestamp; + private volatile Instant latestRefreshTimestamp; public TokenRefreshInterceptor(Config config, HttpClient.Factory factory, Instant latestRefreshTimestamp) { + this(config, latestRefreshTimestamp, + newestConfig -> OpenIDConnectionUtils.resolveOIDCTokenFromAuthConfig(config, newestConfig.getAuthProvider().getConfig(), + factory.newBuilder())); + } + + public TokenRefreshInterceptor(Config config, Instant latestRefreshTimestamp, + Function> remoteRefresh) { this.config = config; + this.remoteRefresh = remoteRefresh; this.latestRefreshTimestamp = latestRefreshTimestamp; - this.factory = factory; } @Override public void before(BasicBuilder headerBuilder, HttpRequest request, RequestTags tags) { - if (isBasicAuth()) { + if (useBasicAuth()) { headerBuilder.header(AUTHORIZATION, HttpClientUtils.basicCredentials(config.getUsername(), config.getPassword())); return; } - if (Utils.isNotNullOrEmpty(config.getOauthToken())) { - headerBuilder.header(AUTHORIZATION, "Bearer " + config.getOauthToken()); + + String token = getEffectiveOauthToken(config); + + if (Utils.isNotNullOrEmpty(token)) { + headerBuilder.header(AUTHORIZATION, "Bearer " + token); } if (isTimeToRefresh()) { refreshToken(headerBuilder); } } - private boolean isBasicAuth() { + private static String getEffectiveOauthToken(Config config) { + if (config.getOauthTokenProvider() != null) { + return config.getOauthTokenProvider().getToken(); + } + if (config.getOauthToken() != null) { + return config.getOauthToken(); + } + return config.getAutoOAuthToken(); + } + + protected boolean useBasicAuth() { + return isBasicAuth(); + } + + final protected boolean isBasicAuth() { return Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword()); } @@ -74,45 +99,48 @@ private boolean isTimeToRefresh() { @Override public CompletableFuture afterFailure(BasicBuilder headerBuilder, HttpResponse response, RequestTags tags) { - if (isBasicAuth()) { + if (shouldFail(response)) { return CompletableFuture.completedFuture(false); } - if (response.code() == HttpURLConnection.HTTP_UNAUTHORIZED) { - return refreshToken(headerBuilder); - } - return CompletableFuture.completedFuture(false); + return refreshToken(headerBuilder); + } + + protected boolean shouldFail(HttpResponse response) { + return useBasicAuth() || response.code() != HttpURLConnection.HTTP_UNAUTHORIZED; } private CompletableFuture refreshToken(BasicBuilder headerBuilder) { if (config.getOauthTokenProvider() != null) { String tokenFromProvider = config.getOauthTokenProvider().getToken(); - if (tokenFromProvider != null && !tokenFromProvider.isEmpty()) { - return CompletableFuture.completedFuture(overrideNewAccessTokenToConfig(tokenFromProvider, headerBuilder, config)); - } + return CompletableFuture.completedFuture(overrideNewAccessTokenToConfig(tokenFromProvider, headerBuilder)); } - if (config.getUserConfiguredOauthToken() != null && !config.getUserConfiguredOauthToken().isEmpty()) { - return CompletableFuture - .completedFuture(overrideNewAccessTokenToConfig(config.getUserConfiguredOauthToken(), headerBuilder, config)); + if (config.getOauthToken() != null) { + return CompletableFuture.completedFuture(false); } Config newestConfig = config.refresh(); final CompletableFuture newAccessToken = extractNewAccessTokenFrom(newestConfig); - return newAccessToken.thenApply(token -> overrideNewAccessTokenToConfig(token, headerBuilder, config)); + return newAccessToken.thenApply(token -> overrideNewAccessTokenToConfig(token, headerBuilder)); } private CompletableFuture extractNewAccessTokenFrom(Config newestConfig) { - if (isAuthProviderOidc(newestConfig) && OpenIDConnectionUtils.idTokenExpired(newestConfig)) { - return OpenIDConnectionUtils.resolveOIDCTokenFromAuthConfig(config, newestConfig.getAuthProvider().getConfig(), - factory.newBuilder()); + if (useRemoteRefresh(newestConfig)) { + // TODO: determine the appropriate fall-back behavior. If the result here is null, do we use the non-remote token + return remoteRefresh.apply(newestConfig); } - return CompletableFuture.completedFuture(newestConfig.getOauthToken()); + return CompletableFuture.completedFuture(getEffectiveOauthToken(newestConfig)); + } + + protected boolean useRemoteRefresh(Config newestConfig) { + // TODO: in a hard failure scenario, should we skip the expired check + return isAuthProviderOidc(newestConfig) && OpenIDConnectionUtils.idTokenExpired(newestConfig); } - private boolean overrideNewAccessTokenToConfig(String newAccessToken, BasicBuilder headerBuilder, Config existConfig) { + private boolean overrideNewAccessTokenToConfig(String newAccessToken, BasicBuilder headerBuilder) { if (Utils.isNotNullOrEmpty(newAccessToken)) { headerBuilder.setHeader(AUTHORIZATION, "Bearer " + newAccessToken); - existConfig.setAutoOAuthToken(newAccessToken); + config.setAutoOAuthToken(newAccessToken); updateLatestRefreshTimestamp(); 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 0c25463bd6a..899e0b9a767 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 @@ -162,10 +162,10 @@ void testWithSystemProperties() { System.setProperty(Config.KUBERNETES_UPLOAD_REQUEST_TIMEOUT_SYSTEM_PROPERTY, "600000"); Config config = new Config(); - assertConfig(config); + assertConfig(config, true); config = new ConfigBuilder().build(); - assertConfig(config); + assertConfig(config, true); } @Test @@ -201,7 +201,7 @@ void testWithBuilder() { .withKeyStorePassphrase("keystorePassphrase") .build(); - assertConfig(config); + assertConfig(config, false); } @Test @@ -244,7 +244,7 @@ void testWithBuilderAndSystemProperties() { .withNamespace("testns") .build(); - assertConfig(config); + assertConfig(config, true); } @Test @@ -292,7 +292,7 @@ void testWithKubeConfig() { assertEquals("https://172.28.128.4:8443/", config.getMasterUrl()); assertEquals("testns", config.getNamespace()); - assertEquals("token", config.getOauthToken()); + assertEquals("token", config.getAutoOAuthToken()); assertTrue(config.getCaCertFile().endsWith("testns/ca.pem".replace("/", File.separator))); assertTrue(new File(config.getCaCertFile()).isAbsolute()); assertEquals(new File(TEST_KUBECONFIG_FILE), config.getFile()); @@ -306,7 +306,7 @@ void testWithKubeConfigAndOverrideContext() { assertEquals("https://172.28.128.4:8443/", config.getMasterUrl()); assertEquals("production", config.getNamespace()); - assertEquals("supertoken", config.getOauthToken()); + assertEquals("supertoken", config.getAutoOAuthToken()); assertTrue(config.getCaCertFile().endsWith("testns/ca.pem".replace("/", File.separator))); assertTrue(new File(config.getCaCertFile()).isAbsolute()); } @@ -320,7 +320,7 @@ void testWithMultipleKubeConfigAndOverrideContext() { assertEquals("https://172.28.128.4:8443/", config.getMasterUrl()); assertEquals("production", config.getNamespace()); - assertEquals("supertoken", config.getOauthToken()); + assertEquals("supertoken", config.getAutoOAuthToken()); assertTrue(config.getCaCertFile().endsWith("testns/ca.pem".replace("/", File.separator))); assertTrue(new File(config.getCaCertFile()).isAbsolute()); } @@ -334,7 +334,7 @@ void testWithKubeConfigAndSystemProperties() { assertNotNull(config); assertEquals("http://somehost:80/", config.getMasterUrl()); assertEquals("testns", config.getNamespace()); - assertEquals("token", config.getOauthToken()); + assertEquals("token", config.getAutoOAuthToken()); assertEquals(new File(TEST_KUBECONFIG_FILE), config.getFile()); } @@ -349,7 +349,7 @@ void testWithKubeConfigAndSytemPropertiesAndBuilder() { assertNotNull(config); assertEquals("http://somehost:80/", config.getMasterUrl()); - assertEquals("token", config.getOauthToken()); + assertEquals("token", config.getAutoOAuthToken()); assertEquals("testns2", config.getNamespace()); } @@ -483,7 +483,7 @@ void honorClientAuthenticatorCommands() throws Exception { Config config = Config.autoConfigure(null); assertNotNull(config); - assertEquals("HELLO WORLD", config.getOauthToken()); + assertEquals("HELLO WORLD", config.getAutoOAuthToken()); } @Test @@ -498,7 +498,7 @@ void should_accept_client_authentication_commands_with_null_args() throws Except Config config = Config.autoConfigure(null); assertNotNull(config); - assertEquals("HELLO", config.getOauthToken()); + assertEquals("HELLO", config.getAutoOAuthToken()); } finally { System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); } @@ -517,7 +517,7 @@ void should_accept_client_authentication_commands_args_with_spaces() throws Exce Config config = Config.autoConfigure(null); assertNotNull(config); - assertEquals("HELLO W O R L D", config.getOauthToken()); + assertEquals("HELLO W O R L D", config.getAutoOAuthToken()); } finally { System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); } @@ -536,7 +536,7 @@ void should_accept_client_authentication_commands_with_spaces() throws Exception Config config = Config.autoConfigure(null); assertNotNull(config); - assertEquals("HELLO WORLD", config.getOauthToken()); + assertEquals("HELLO WORLD", config.getAutoOAuthToken()); } finally { System.clearProperty(Config.KUBERNETES_KUBECONFIG_FILE); } @@ -549,7 +549,9 @@ void shouldBeUsedTokenSuppliedByProvider() { .withOauthTokenProvider(() -> "PROVIDER_TOKEN") .build(); - assertEquals("PROVIDER_TOKEN", config.getOauthToken()); + // this is mostly a configuration error, and + // the provider does not modify the oauthtoken field + assertEquals("oauthToken", config.getOauthToken()); } @Test @@ -567,7 +569,7 @@ void testKubeConfigWithAuthConfigProvider() throws URISyntaxException { assertEquals("https://172.28.128.4:8443/", config.getMasterUrl()); assertEquals( "eyJraWQiOiJDTj1vaWRjaWRwLnRyZW1vbG8ubGFuLCBPVT1EZW1vLCBPPVRybWVvbG8gU2VjdXJpdHksIEw9QXJsaW5ndG9uLCBTVD1WaXJnaW5pYSwgQz1VUy1DTj1rdWJlLWNhLTEyMDIxNDc5MjEwMzYwNzMyMTUyIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL29pZGNpZHAudHJlbW9sby5sYW46ODQ0My9hdXRoL2lkcC9PaWRjSWRQIiwiYXVkIjoia3ViZXJuZXRlcyIsImV4cCI6MTQ4MzU0OTUxMSwianRpIjoiMm96US15TXdFcHV4WDlHZUhQdy1hZyIsImlhdCI6MTQ4MzU0OTQ1MSwibmJmIjoxNDgzNTQ5MzMxLCJzdWIiOiI0YWViMzdiYS1iNjQ1LTQ4ZmQtYWIzMC0xYTAxZWU0MWUyMTgifQ.w6p4J_6qQ1HzTG9nrEOrubxIMb9K5hzcMPxc9IxPx2K4xO9l-oFiUw93daH3m5pluP6K7eOE6txBuRVfEcpJSwlelsOsW8gb8VJcnzMS9EnZpeA0tW_p-mnkFc3VcfyXuhe5R3G7aa5d8uHv70yJ9Y3-UhjiN9EhpMdfPAoEB9fYKKkJRzF7utTTIPGrSaSU6d2pcpfYKaxIwePzEkT4DfcQthoZdy9ucNvvLoi1DIC-UocFD8HLs8LYKEqSxQvOcvnThbObJ9af71EwmuE21fO5KzMW20KtAeget1gnldOosPtz1G5EwvaQ401-RPQzPGMVBld0_zMCAwZttJ4knw", - config.getOauthToken()); + config.getAutoOAuthToken()); } @Test @@ -605,13 +607,17 @@ void testEmptyConfig() { .satisfies(e -> assertThat(e.getUserAgent()).isNotNull()); } - private void assertConfig(Config config) { + private void assertConfig(Config config, boolean autoToken) { assertNotNull(config); assertTrue(config.isTrustCerts()); assertTrue(config.isDisableHostnameVerification()); assertEquals("http://somehost:80/", config.getMasterUrl()); assertEquals("testns", config.getNamespace()); - assertEquals("token", config.getOauthToken()); + if (autoToken) { + assertEquals("token", config.getAutoOAuthToken()); + } else { + assertEquals("token", config.getOauthToken()); + } assertEquals("user", config.getUsername()); assertEquals("pass", config.getPassword()); assertEquals("/path/to/cert", config.getCaCertFile()); diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptorTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptorTest.java index eeccf0dbad8..b0e96819316 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptorTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/TokenRefreshInterceptorTest.java @@ -115,7 +115,7 @@ void refreshShouldNotOverwriteExistingToken() throws Exception { final boolean result = tokenRefreshInterceptor .afterFailure(new StandardHttpRequest.Builder(), new TestHttpResponse<>().withCode(401), null).get(); // Then - assertThat(result).isTrue(); + assertThat(result).isFalse(); assertThat(originalConfig).hasFieldOrPropertyWithValue("oauthToken", "existing-token"); } @@ -132,7 +132,7 @@ void refresh_whenNoAuthProvider_thenShouldInheritTokenFromOldConfig() throws Exc final boolean result = tokenRefreshInterceptor .afterFailure(new StandardHttpRequest.Builder(), new TestHttpResponse<>().withCode(401), null).get(); // Then - assertThat(result).isTrue(); + assertThat(result).isFalse(); assertThat(originalConfig).hasFieldOrPropertyWithValue("oauthToken", "existing-token"); } diff --git a/openshift-client/src/main/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptor.java b/openshift-client/src/main/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptor.java index d79a1d59b5a..d38453af620 100644 --- a/openshift-client/src/main/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptor.java +++ b/openshift-client/src/main/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptor.java @@ -20,17 +20,14 @@ import io.fabric8.kubernetes.api.model.authorization.v1.SelfSubjectAccessReview; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.KubernetesClientException; -import io.fabric8.kubernetes.client.http.BasicBuilder; import io.fabric8.kubernetes.client.http.HttpClient; import io.fabric8.kubernetes.client.http.HttpRequest; import io.fabric8.kubernetes.client.http.HttpResponse; -import io.fabric8.kubernetes.client.http.Interceptor; import io.fabric8.kubernetes.client.utils.HttpClientUtils; import io.fabric8.kubernetes.client.utils.OpenIDConnectionUtils; import io.fabric8.kubernetes.client.utils.Serialization; import io.fabric8.kubernetes.client.utils.TokenRefreshInterceptor; import io.fabric8.kubernetes.client.utils.URLUtils; -import io.fabric8.kubernetes.client.utils.Utils; import io.fabric8.openshift.api.model.LocalResourceAccessReview; import io.fabric8.openshift.api.model.LocalSubjectAccessReview; import io.fabric8.openshift.api.model.ResourceAccessReview; @@ -43,6 +40,7 @@ import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.time.Instant; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; @@ -57,7 +55,7 @@ * Controls openshift authentication. It will be based upon an oauth token that can either come from a "login" or from the * config / token provider. */ -public class OpenShiftOAuthInterceptor implements Interceptor { +public class OpenShiftOAuthInterceptor extends TokenRefreshInterceptor { private static final Logger LOGGER = LoggerFactory.getLogger(OpenShiftOAuthInterceptor.class); @@ -77,60 +75,22 @@ public class OpenShiftOAuthInterceptor implements Interceptor { HasMetadata.getPlural(SubjectAccessReview.class), HasMetadata.getPlural(SelfSubjectAccessReview.class)))); - private final HttpClient client; - private final Config config; - public OpenShiftOAuthInterceptor(HttpClient client, Config config) { - this.client = client; - this.config = config; + super(config, Instant.now(), + newestConfig -> authorize(config, client).thenApply(token -> persistNewOAuthTokenIntoKubeConfig(config, token))); } @Override - public void before(BasicBuilder builder, HttpRequest httpRequest, RequestTags tags) { - setAuthHeader(builder, config.getOauthToken()); + protected boolean useBasicAuth() { + return false; // openshift does not support the basic auth header } @Override - public CompletableFuture afterFailure(BasicBuilder builder, HttpResponse response, RequestTags tags) { - if (shouldProceed(response.request(), response)) { - return CompletableFuture.completedFuture(false); - } - - // use the original config, not the refreshed, as the username / password could be programmatically set on the Config or RequestConfig - if (Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword())) { - // TODO: we could make all concurrent refresh requests return the same future - return authorize().thenApply(t -> persistNewOAuthTokenIntoKubeConfig(builder, t)); - } - return CompletableFuture.completedFuture(refreshFromConfig(builder)); + protected boolean useRemoteRefresh(Config newestConfig) { + return isBasicAuth(); // if we have both username, and password, try to refresh } - private boolean refreshFromConfig(BasicBuilder builder) { - if (config.getOauthTokenProvider() != null) { - String tokenFromProvider = config.getOauthTokenProvider().getToken(); - if (tokenFromProvider != null && !tokenFromProvider.isEmpty()) { - setAuthHeader(builder, tokenFromProvider); - } - } - if (config.getUserConfiguredOauthToken() != null && !config.getUserConfiguredOauthToken().isEmpty()) { - setAuthHeader(builder, config.getUserConfiguredOauthToken()); - } - Config newestConfig = config.refresh(); // does some i/o work, but for now we'll consider this non-blocking - String oauthToken = newestConfig.getAutoOAuthToken(); - if (oauthToken != null) { - config.setAutoOAuthToken(oauthToken); - } - return setAuthHeader(builder, config.getOauthToken()); - } - - private boolean setAuthHeader(BasicBuilder builder, String token) { - if (token != null) { - builder.setHeader(AUTHORIZATION, String.format("Bearer %s", token)); - return true; - } - return false; - } - - private CompletableFuture authorize() { + private static CompletableFuture authorize(Config config, HttpClient client) { HttpClient.DerivedClientBuilder builder = client.newBuilder(); builder.addOrReplaceInterceptor(TokenRefreshInterceptor.NAME, null); HttpClient clone = builder.build(); @@ -179,7 +139,9 @@ private CompletableFuture authorize() { }); } - private boolean shouldProceed(HttpRequest request, HttpResponse response) { + @Override + protected boolean shouldFail(HttpResponse response) { + HttpRequest request = response.request(); String url = request.uri().toString(); String method = request.method(); // always retry in case of authorization endpoints; since they also return 200 when no @@ -190,21 +152,16 @@ private boolean shouldProceed(HttpRequest request, HttpResponse response) { return response.code() != HTTP_UNAUTHORIZED; } - private boolean persistNewOAuthTokenIntoKubeConfig(BasicBuilder builder, String token) { + private static String persistNewOAuthTokenIntoKubeConfig(Config config, String token) { if (token != null) { - config.setAutoOAuthToken(token); try { - // TODO: we may need some protection here or in the persistKubeConfigWithUpdatedAuthInfo - // if the user has modified the username via the requestconfig are we writing a valid value? OpenIDConnectionUtils.persistKubeConfigWithUpdatedAuthInfo(config, a -> a.setToken(token)); } catch (IOException e) { LOGGER.warn("failure while persisting new token into KUBECONFIG", e); } - // If token was obtained, then retry request using the obtained token. - return setAuthHeader(builder, token); } - return refreshFromConfig(builder); + return token; } } diff --git a/openshift-client/src/test/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptorTest.java b/openshift-client/src/test/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptorTest.java index 91cd3181d31..c78333b23f0 100644 --- a/openshift-client/src/test/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptorTest.java +++ b/openshift-client/src/test/java/io/fabric8/openshift/client/internal/OpenShiftOAuthInterceptorTest.java @@ -127,8 +127,7 @@ void afterFailure_whenTokenSetByUser_thenNoRefresh() { null); // Then - assertThat(result).isCompletedWithValue(true); - verify(builder).setHeader("Authorization", "Bearer token-set-by-user"); + assertThat(result).isCompletedWithValue(false); } @Test @@ -147,8 +146,8 @@ void afterFailure_whenOAuthTokenProviderPresent_thenUseTokenFromProvider() { .withRequest(new StandardHttpRequest(null, URI.create("http://localhost"), "GET", null)), null); - // Then - assertThat(result).isCompletedWithValue(false); + // Then - could try to detect that it hasn't changed, but for now we'll just proceed with the same + assertThat(result).isCompletedWithValue(true); verify(builder).setHeader("Authorization", "Bearer token-from-oauthtokenprovider"); } @@ -157,6 +156,7 @@ void afterFailure_withUsernamePassword_thenShouldAuthorize() { try (MockedStatic kubeConfigUtilsMockedStatic = mockStatic(KubeConfigUtils.class)) { // Given Config config = mock(Config.class, RETURNS_DEEP_STUBS); + when(config.getOauthTokenProvider()).thenReturn(null); io.fabric8.kubernetes.api.model.Config kubeConfigContent = mock(io.fabric8.kubernetes.api.model.Config.class); HttpClient client = mock(HttpClient.class); HttpRequest.Builder builder = mock(HttpRequest.Builder.class, RETURNS_SELF); @@ -263,7 +263,6 @@ private Config mockConfigRefresh() { Config refreshedConfig = mock(Config.class); when(refreshedConfig.getAutoOAuthToken()).thenReturn("token"); when(config.refresh()).thenReturn(refreshedConfig); - when(config.getOauthToken()).thenReturn("token"); return config; }