-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Modified kubernetes openapi http client filter to support reactive an…
…d blocking token loaders (#850)
- Loading branch information
Showing
11 changed files
with
242 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
...java/io/micronaut/kubernetes/client/openapi/credential/ReactiveKubernetesTokenLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
/* | ||
* Copyright 2017-2025 original authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.micronaut.kubernetes.client.openapi.credential; | ||
|
||
import io.micronaut.core.annotation.NonNull; | ||
import io.micronaut.core.async.annotation.SingleResult; | ||
import org.reactivestreams.Publisher; | ||
|
||
/** | ||
* The loader for bearer token used in kubernetes api service authentication. | ||
*/ | ||
public interface ReactiveKubernetesTokenLoader extends TokenLoader { | ||
|
||
/** | ||
* Gets a bearer token for request authentication. | ||
* | ||
* @return bearer token | ||
*/ | ||
@SingleResult | ||
@NonNull Publisher<String> getToken(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
26 changes: 26 additions & 0 deletions
26
...i-common/src/main/java/io/micronaut/kubernetes/client/openapi/credential/TokenLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
/* | ||
* Copyright 2017-2025 original authors | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package io.micronaut.kubernetes.client.openapi.credential; | ||
|
||
import io.micronaut.core.annotation.Internal; | ||
import io.micronaut.core.order.Ordered; | ||
|
||
/** | ||
* Interface for blocking and reactive kubernetes token loaders. | ||
*/ | ||
@Internal | ||
public interface TokenLoader extends Ordered { | ||
} |
138 changes: 138 additions & 0 deletions
138
.../test/groovy/io/micronaut/kubernetes/client/openapi/KubernetesHttpClientFilterSpec.groovy
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package io.micronaut.kubernetes.client.openapi | ||
|
||
import io.micronaut.context.ApplicationContext | ||
import io.micronaut.context.ProviderUtils | ||
import io.micronaut.core.util.StringUtils | ||
import io.micronaut.http.HttpMethod | ||
import io.micronaut.http.HttpResponse | ||
import io.micronaut.http.MutableHttpRequest | ||
import io.micronaut.http.filter.ClientFilterChain | ||
import io.micronaut.http.simple.SimpleHttpRequest | ||
import io.micronaut.kubernetes.client.openapi.config.KubeConfig | ||
import io.micronaut.kubernetes.client.openapi.config.KubeConfigLoader | ||
import io.micronaut.kubernetes.client.openapi.credential.KubernetesTokenLoader | ||
import io.micronaut.kubernetes.client.openapi.credential.ReactiveKubernetesTokenLoader | ||
import io.micronaut.kubernetes.client.openapi.credential.TokenLoader | ||
import org.reactivestreams.Publisher | ||
import reactor.core.publisher.Mono | ||
import spock.lang.Specification | ||
|
||
class KubernetesHttpClientFilterSpec extends Specification { | ||
|
||
private static final def BASE_MAP = ["current-context": "test-context"] | ||
private static final def CONTEXT_MAP = [contexts: [[name: "test-context", context: [cluster: "test-cluster", user: "test-user"]]]] | ||
private static final def CLUSTER_MAP = [clusters: [[name: "test-cluster", cluster: ["server": "test-server"]]]] | ||
private static final def USER_MAP = [users: [[name: "test-user", user: ["username": "test-username", "password": "test-password"]]]] | ||
private static final def KUBE_CONFIG_MAP = BASE_MAP + CONTEXT_MAP + CLUSTER_MAP + USER_MAP | ||
|
||
ApplicationContext applicationContext | ||
KubeConfigLoader kubeConfigLoader | ||
|
||
def setup() { | ||
applicationContext = Stub(ApplicationContext) | ||
kubeConfigLoader = Stub(KubeConfigLoader) | ||
} | ||
|
||
def 'filter uses username and password authentication'() { | ||
given: | ||
def filter = new KubernetesHttpClientFilter(ProviderUtils.memoized(() -> kubeConfigLoader), applicationContext, null) | ||
def request = new SimpleHttpRequest<String>(HttpMethod.GET, "/test", "value") | ||
def filterChain = new CustomClientFilterChain() | ||
|
||
and: | ||
def config = new KubeConfig(KUBE_CONFIG_MAP) | ||
kubeConfigLoader.getKubeConfig() >> config | ||
|
||
when: | ||
Mono.from(filter.doFilter(request, filterChain)).block() | ||
|
||
then: | ||
filterChain.getAuthHeaderValue() == "Basic " + new String(Base64.getEncoder().encode("test-username:test-password".getBytes())) | ||
} | ||
|
||
def 'filter uses token from blocking loader'() { | ||
given: | ||
def filter = new KubernetesHttpClientFilter(ProviderUtils.memoized(() -> kubeConfigLoader), applicationContext, null) | ||
def request = new SimpleHttpRequest<String>(HttpMethod.GET, "/test", "value") | ||
def filterChain = new CustomClientFilterChain() | ||
|
||
and: | ||
kubeConfigLoader.getKubeConfig() >> null | ||
|
||
and: | ||
def loader1 = new BlockingLoader("test1") | ||
def loader2 = new ReactiveLoader("test2") | ||
applicationContext.getBeansOfType(TokenLoader.class) >> [loader1, loader2] | ||
|
||
when: | ||
Mono.from(filter.doFilter(request, filterChain)).block() | ||
|
||
then: | ||
filterChain.getAuthHeaderValue() == "Bearer test1" | ||
} | ||
|
||
def 'filter uses token from reactive loader'() { | ||
given: | ||
def filter = new KubernetesHttpClientFilter(ProviderUtils.memoized(() -> kubeConfigLoader), applicationContext, null) | ||
def request = new SimpleHttpRequest<String>(HttpMethod.GET, "/test", "value") | ||
def filterChain = new CustomClientFilterChain() | ||
|
||
and: | ||
kubeConfigLoader.getKubeConfig() >> null | ||
|
||
and: | ||
def loader1 = new BlockingLoader(null) | ||
def loader2 = new ReactiveLoader("test2") | ||
applicationContext.getBeansOfType(TokenLoader.class) >> [loader1, loader2] | ||
|
||
when: | ||
Mono.from(filter.doFilter(request, filterChain)).block() | ||
|
||
then: | ||
filterChain.getAuthHeaderValue() == "Bearer test2" | ||
} | ||
|
||
class CustomClientFilterChain implements ClientFilterChain { | ||
private String authHeaderValue | ||
|
||
String getAuthHeaderValue() { | ||
return authHeaderValue | ||
} | ||
|
||
@Override | ||
Publisher<? extends HttpResponse<?>> proceed(MutableHttpRequest<?> request) { | ||
authHeaderValue = request.getHeaders().getAuthorization().orElse(StringUtils.EMPTY_STRING) | ||
return Mono.empty() | ||
} | ||
} | ||
|
||
static class BlockingLoader implements KubernetesTokenLoader { | ||
private final String token | ||
|
||
private BlockingLoader(String token) { | ||
this.token = token | ||
} | ||
|
||
@Override | ||
String getToken() { | ||
return token | ||
} | ||
} | ||
|
||
static class ReactiveLoader implements ReactiveKubernetesTokenLoader { | ||
private final String token | ||
|
||
private ReactiveLoader(String token) { | ||
this.token = token | ||
} | ||
|
||
@Override | ||
Publisher<String> getToken() { | ||
return Mono.fromCallable(() -> loadToken()) | ||
} | ||
|
||
private String loadToken() { | ||
return token | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters