Skip to content

Commit

Permalink
Strimzi OAuth substitutions
Browse files Browse the repository at this point in the history
  • Loading branch information
ozangunalp committed Oct 26, 2023
1 parent 81d9000 commit abdfa22
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 28 deletions.
5 changes: 5 additions & 0 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4256,6 +4256,11 @@
<artifactId>kafka-oauth-client</artifactId>
<version>${strimzi-oauth.version}</version>
</dependency>
<dependency>
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-common</artifactId>
<version>${strimzi-oauth.version}</version>
</dependency>
<dependency>
<groupId>io.strimzi</groupId>
<artifactId>strimzi-test-container</artifactId>
Expand Down
7 changes: 7 additions & 0 deletions docs/src/main/asciidoc/kafka.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1971,12 +1971,19 @@ First, add the following dependency to your application:
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-client</artifactId>
</dependency>
<!-- if compiling to native you'd need also the following dependency -->
<dependency>
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-common</artifactId>
</dependency>
----

[source,gradle,role="secondary asciidoc-tabs-target-sync-gradle"]

Check warning on line 1981 in docs/src/main/asciidoc/kafka.adoc

View workflow job for this annotation

GitHub Actions / Linting with Vale

[vale] reported by reviewdog 🐶 [Quarkus.CaseSensitiveTerms] Use 'Gradle' rather than 'gradle'. Raw Output: {"message": "[Quarkus.CaseSensitiveTerms] Use 'Gradle' rather than 'gradle'.", "location": {"path": "docs/src/main/asciidoc/kafka.adoc", "range": {"start": {"line": 1981, "column": 41}}}, "severity": "INFO"}
.build.gradle
----
implementation("io.strimzi:kafka-oauth-client")
// if compiling to native you'd need also the following dependency
implementation("io.strimzi:kafka-oauth-common")
----

This dependency provides the callback handler required to handle the OAuth workflow.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,6 @@ public void build(

handleAvro(reflectiveClass, proxies, serviceProviders, sslNativeSupport, capabilities);
handleOpenTracing(reflectiveClass, capabilities);
handleStrimziOAuth(curateOutcomeBuildItem, reflectiveClass);

}

Expand Down Expand Up @@ -330,31 +329,6 @@ private void handleOpenTracing(BuildProducer<ReflectiveClassBuildItem> reflectiv
.build());
}

private void handleStrimziOAuth(CurateOutcomeBuildItem curateOutcomeBuildItem,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
if (!QuarkusClassLoader.isClassPresentAtRuntime("io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler")) {
return;
}

reflectiveClass
.produce(ReflectiveClassBuildItem.builder("io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler")
.methods().fields().build());

if (curateOutcomeBuildItem.getApplicationModel().getDependencies().stream().anyMatch(
x -> x.getGroupId().equals("org.keycloak") && x.getArtifactId().equals("keycloak-core"))) {
reflectiveClass.produce(ReflectiveClassBuildItem.builder("org.keycloak.jose.jws.JWSHeader",
"org.keycloak.representations.AccessToken",
"org.keycloak.representations.AccessToken$Access",
"org.keycloak.representations.AccessTokenResponse",
"org.keycloak.representations.IDToken",
"org.keycloak.representations.JsonWebToken",
"org.keycloak.jose.jwk.JSONWebKeySet",
"org.keycloak.jose.jwk.JWK",
"org.keycloak.json.StringOrArrayDeserializer",
"org.keycloak.json.StringListMapDeserializer").methods().fields().build());
}
}

private void handleAvro(BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
BuildProducer<NativeImageProxyDefinitionBuildItem> proxies,
BuildProducer<ServiceProviderBuildItem> serviceProviders,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package io.quarkus.kafka.client.deployment;

import io.quarkus.bootstrap.classloading.QuarkusClassLoader;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.pkg.builditem.CurateOutcomeBuildItem;

public class StrimziOAuthProcessor {

@BuildStep
public void handleStrimziOAuth(CurateOutcomeBuildItem curateOutcomeBuildItem,
BuildProducer<ReflectiveClassBuildItem> reflectiveClass) {
if (!QuarkusClassLoader.isClassPresentAtRuntime("io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler")) {
return;
}

reflectiveClass
.produce(ReflectiveClassBuildItem.builder(
"io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler")
.methods().fields().build());

if (curateOutcomeBuildItem.getApplicationModel().getDependencies().stream().anyMatch(
x -> x.getGroupId().equals("org.keycloak") && x.getArtifactId().equals("keycloak-core"))) {
reflectiveClass.produce(ReflectiveClassBuildItem.builder("org.keycloak.jose.jws.JWSHeader",
"org.keycloak.representations.AccessToken",
"org.keycloak.representations.AccessToken$Access",
"org.keycloak.representations.AccessTokenResponse",
"org.keycloak.representations.IDToken",
"org.keycloak.representations.JsonWebToken",
"org.keycloak.jose.jwk.JSONWebKeySet",
"org.keycloak.jose.jwk.JWK",
"org.keycloak.json.StringOrArrayDeserializer",
"org.keycloak.json.StringListMapDeserializer").methods().fields().build());
}
}

}
5 changes: 5 additions & 0 deletions extensions/kafka-client/runtime/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
<artifactId>quarkus-kubernetes-service-binding</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-common</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>io.quarkus</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package io.smallrye.reactive.kafka.graal;

import java.util.function.BooleanSupplier;

import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.spi.json.JacksonJsonNodeJsonProvider;
import com.jayway.jsonpath.spi.json.JacksonJsonProvider;
import com.jayway.jsonpath.spi.json.JsonProvider;
import com.jayway.jsonpath.spi.mapper.JacksonMappingProvider;
import com.jayway.jsonpath.spi.mapper.MappingProvider;
import com.oracle.svm.core.annotate.Alias;
import com.oracle.svm.core.annotate.RecomputeFieldValue;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;

final class HasStrimzi implements BooleanSupplier {

@Override
public boolean getAsBoolean() {
try {
KafkaSubstitutions.class.getClassLoader()
.loadClass("io.strimzi.kafka.oauth.client.JaasClientOauthLoginCallbackHandler");
return true;
} catch (Exception e) {
return false;
}
}
}

@TargetClass(className = "com.jayway.jsonpath.internal.filter.ValueNodes", innerClass = "JsonNode", onlyWith = HasStrimzi.class)
final class Target_com_jayway_jsonpath_internal_filter_ValueNodes_JsonNode {
@Alias
private Object json;
@Alias
private boolean parsed;

@Substitute
public Object parse(Predicate.PredicateContext ctx) {
try {
return parsed ? json : new JacksonJsonProvider().parse(json.toString());
} catch (Throwable e) {
throw new IllegalArgumentException(e);
}
}
}

@TargetClass(className = "com.jayway.jsonpath.internal.filter.ValueNode", onlyWith = HasStrimzi.class)
final class Target_com_jayway_jsonpath_internal_filter_ValueNode {

@Substitute
private static boolean isJson(Object o) {
if (o == null || !(o instanceof String)) {
return false;
}
String str = o.toString().trim();
if (str.length() <= 1) {
return false;
}
char c0 = str.charAt(0);
char c1 = str.charAt(str.length() - 1);
if ((c0 == '[' && c1 == ']') || (c0 == '{' && c1 == '}')) {
try {
new JacksonJsonProvider().parse(str);
return true;
} catch (Exception e) {
return false;
}
}
return false;
}
}

@TargetClass(className = "com.jayway.jsonpath.internal.DefaultsImpl", onlyWith = HasStrimzi.class)
final class Target_com_jayway_jsonpath_internal_DefaultsImpl {

@RecomputeFieldValue(kind = RecomputeFieldValue.Kind.FromAlias)
@Alias
public static Target_com_jayway_jsonpath_internal_DefaultsImpl INSTANCE = new Target_com_jayway_jsonpath_internal_DefaultsImpl();

@Substitute
public JsonProvider jsonProvider() {
return new JacksonJsonNodeJsonProvider();
}

@Substitute
public MappingProvider mappingProvider() {
return new JacksonMappingProvider();
}
}
16 changes: 14 additions & 2 deletions integration-tests/kafka-oauth-keycloak/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-client</artifactId>
</dependency>
<!-- required for native compilation as strimzi substitutions require these classes -->
<dependency>
<groupId>io.strimzi</groupId>
<artifactId>kafka-oauth-common</artifactId>
</dependency>

<!-- test dependencies -->
<dependency>
Expand Down Expand Up @@ -71,6 +76,11 @@
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-keycloak-server</artifactId>
<scope>test</scope>
</dependency>

<!-- Minimal test dependencies to *-deployment artifacts for consistent build order -->
<dependency>
Expand Down Expand Up @@ -174,7 +184,8 @@
<skip>false</skip>
<systemPropertyVariables>
<!-- Configure the app to test to resolve "keycloak" hostname to the Docker hostname -->
<jdk.net.hosts.file>target/hosts</jdk.net.hosts.file>
<keycloak.docker.image>${keycloak.docker.image}</keycloak.docker.image>
<keycloak.realm.json>${project.basedir}/src/test/resources/keycloak/realms/kafka-authz-realm.json</keycloak.realm.json>
</systemPropertyVariables>
</configuration>
</plugin>
Expand All @@ -183,7 +194,8 @@
<configuration>
<skip>false</skip>
<systemPropertyVariables>
<quarkus.test.arg-line>-Djdk.net.hosts.file=${basedir}/target/hosts</quarkus.test.arg-line>
<keycloak.docker.image>${keycloak.docker.image}</keycloak.docker.image>
<keycloak.realm.json>${project.basedir}/src/test/resources/keycloak/realms/kafka-authz-realm.json</keycloak.realm.json>
</systemPropertyVariables>
</configuration>
</plugin>
Expand Down

0 comments on commit abdfa22

Please sign in to comment.