Java

java programming

Java 21 and Maven Error PKIX when Connecting to Self Signed Nexus Registry

Had this error while doing a maven build

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

With a complete error log,

$ mvn clean package -s settings.xml

.......

[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[ERROR] Unresolveable build extension: Plugin com.redhat.quarkus.platform:quarkus-maven-plugin:3.15.3.SP1-redhat-00002 or one of its dependencies could not be resolved: Failed to collect dependencies at com.redhat.quarkus.platform:quarkus-maven-plugin:jar:3.15.3.SP1-redhat-00002 -> io.quarkus:quarkus-bootstrap-maven-resolver:jar:3.15.3.redhat-00004 -> io.smallrye.beanbag:smallrye-beanbag-maven:jar:1.5.2.redhat-00001 -> io.smallrye.beanbag:smallrye-beanbag-sisu:jar:1.5.2.redhat-00001 -> javax.inject:javax.inject:jar:1.0.0.redhat-00014 @
[ERROR] Non-resolvable import POM: The following artifacts could not be resolved: com.redhat.quarkus.platform:quarkus-camel-bom:pom:3.15.3.SP1-redhat-00002 (present, but unavailable): Could not transfer artifact com.redhat.quarkus.platform:quarkus-camel-bom:pom:3.15.3.SP1-redhat-00002 from/to mvn-repository (https://nexus/maven-group/): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target @ line 32, column 25

But somehow the previous solution on my previous post is not working. Maybe because of a different Java version or Maven version. So I need to find another solution, and this is what was working on my end.

First we need to take the self-signed certificate that belongs to the remote Nexus instance

$ echo "" | openssl s_client -connect nexus:8443  -showcerts 2>/dev/null | openssl x509 -out nexus.crt

Import it into our key

$ keytool -import -alias mycert -keystore /tmp/customcacerts -file nexus.crt -storepass changeit -noprompt

And use it on our Maven build

$ ./mvnw -Djavax.net.ssl.trustStore=/tmp/customcacerts \
        -Djavax.net.ssl.trustStorePassword=changeit clean install \ 
		-s settings.xml 

Everything is working well after that.

Maven Error PKIX When Connecting to Self Signed Nexus Repository

Had this error while doing a maven build

PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

With a complete error log,

$ mvn clean package -s settings.xml

.......

[ERROR] [ERROR] Some problems were encountered while processing the POMs:
[ERROR] Unresolveable build extension: Plugin com.redhat.quarkus.platform:quarkus-maven-plugin:3.15.3.SP1-redhat-00002 or one of its dependencies could not be resolved: Failed to collect dependencies at com.redhat.quarkus.platform:quarkus-maven-plugin:jar:3.15.3.SP1-redhat-00002 -> io.quarkus:quarkus-bootstrap-maven-resolver:jar:3.15.3.redhat-00004 -> io.smallrye.beanbag:smallrye-beanbag-maven:jar:1.5.2.redhat-00001 -> io.smallrye.beanbag:smallrye-beanbag-sisu:jar:1.5.2.redhat-00001 -> javax.inject:javax.inject:jar:1.0.0.redhat-00014 @
[ERROR] Non-resolvable import POM: The following artifacts could not be resolved: com.redhat.quarkus.platform:quarkus-camel-bom:pom:3.15.3.SP1-redhat-00002 (present, but unavailable): Could not transfer artifact com.redhat.quarkus.platform:quarkus-camel-bom:pom:3.15.3.SP1-redhat-00002 from/to mvn-repository (https://nexus/maven-group/): PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target @ line 32, column 25
[ERROR] 'dependencies.dependency.version' for org.apache.camel.quarkus:camel-quarkus-direct:jar is missing. @ line 45, column 21
[ERROR] 'dependencies.dependency.version' for org.apache.camel.quarkus:camel-quarkus-jackson:jar is missing. @ line 49, column 21
[ERROR] 'dependencies.dependency.version' for org.apache.camel.quarkus:camel-quarkus-rest-openapi:jar is missing. @ line 53, column 21
[ERROR] 'dependencies.dependency.version' for org.apache.camel.quarkus:camel-quarkus-rest:jar is missing. @ line 57, column 21
 @
[ERROR] The build could not read 1 project -> [Help 1]

Workaround is quite simple,

$ mvn -Dmaven.wagon.http.ssl.insecure=true clean package -s settings.xml

Build a Native Quarkus and Camel Application using Mandrel and Docker

Apache Camel is a Java framework for routing and integration, and when we talk about integration means we are talking about lightweight and fast response time. And this is where Apache Camel and Quarkus comes into the picture.

Utilizing Quarkus capability of native compilation, we can compile our Camel Framework application into a native application without the necessity of using JVM. Therefore making a lightweight Apache Camel into more lighweight and faster.

For this project, we will start with a simple Maven file

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.edw</groupId>
    <artifactId>quarkus-camel-native</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <compiler-plugin.version>3.13.0</compiler-plugin.version>
        <maven.compiler.release>21</maven.compiler.release>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
        <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
        <quarkus.platform.version>3.16.3</quarkus.platform.version>
        <skipITs>true</skipITs>
        <surefire-plugin.version>3.5.0</surefire-plugin.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>${quarkus.platform.artifact-id}</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-camel-bom</artifactId>
                <version>${quarkus.platform.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-direct</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.camel.quarkus</groupId>
            <artifactId>camel-quarkus-rest</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-junit5</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>${quarkus.platform.group-id}</groupId>
                <artifactId>quarkus-maven-plugin</artifactId>
                <version>${quarkus.platform.version}</version>
                <extensions>true</extensions>
                <executions>
                    <execution>
                        <goals>
                            <goal>build</goal>
                            <goal>generate-code</goal>
                            <goal>generate-code-tests</goal>
                            <goal>native-image-agent</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${compiler-plugin.version}</version>
                <configuration>
                    <parameters>true</parameters>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <configuration>
                    <systemPropertyVariables>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
            <plugin>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>${surefire-plugin.version}</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>integration-test</goal>
                            <goal>verify</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <systemPropertyVariables>
                        <native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
                        <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
                        <maven.home>${maven.home}</maven.home>
                    </systemPropertyVariables>
                </configuration>
            </plugin>
        </plugins>
    </build>

    <profiles>
        <profile>
            <id>native</id>
            <activation>
                <property>
                    <name>native</name>
                </property>
            </activation>
            <properties>
                <skipITs>false</skipITs>
                <quarkus.native.enabled>true</quarkus.native.enabled>
            </properties>
        </profile>
    </profiles>

</project>

a properties file,

# default
quarkus.http.port=8080
quarkus.log.level=INFO
quarkus.log.category."com.edw".level=DEBUG

quarkus.log.console.format=%d{yyyy-MM-dd HH:mm:ss,SSS} %h %N[%i] %-5p [%c{3.}] (%t) %s%e%n

# disable sending anonymous statistics
quarkus.analytics.disabled=true

and with a simple Java file,

package com.edw.route;

import jakarta.enterprise.context.ApplicationScoped;
import org.apache.camel.builder.RouteBuilder;

@ApplicationScoped
public class HelloWorldRoute extends RouteBuilder {

    @Override
    public void configure() throws Exception {
        rest("/api")
                .get("/hello-world")
                .produces("application/json")
                .to("direct:hello-world");

        from("direct:hello-world")
                .routeId("hello-world-api")
                .log("calling getHelloWorld")
                .setBody(constant("{\"hello\":\"world\"}"));
    }
}

and finally, a Dockerfile

## Stage 1 : build with maven builder image with native capabilities
FROM quay.io/quarkus/ubi-quarkus-mandrel-builder-image:jdk-21 AS build
COPY --chown=quarkus:quarkus --chmod=0755 mvnw /code/mvnw
COPY --chown=quarkus:quarkus .mvn /code/.mvn
COPY --chown=quarkus:quarkus pom.xml /code/
USER quarkus
WORKDIR /code
RUN ./mvnw -B org.apache.maven.plugins:maven-dependency-plugin:3.1.2:go-offline
COPY src /code/src
RUN ./mvnw package -Dnative

## Stage 2 : create the docker final image
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
COPY --from=build /code/target/*-runner /work/application

# set up permissions for user `1001`
RUN chmod 775 /work /work/application \
  && chown -R 1001 /work \
  && chmod -R "g+rwX" /work \
  && chown -R 1001:root /work

EXPOSE 8080
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]

As we can see, it is a multi-stage docker build and we are using Mandrel to compile Quarkus into a native application. Next is to do a docker build, and see our Quarkus add compiled into native

$ podman build -t quarkus-camel-native -f multistage.dockerfile  .

[1/8] Initializing...                                                                                   (11.5s @ 0.12GB)
 Java version: 21.0.5+11-LTS, vendor version: Mandrel-23.1.5.0-Final
 Graal compiler: optimization level: 2, target machine: x86-64-v3
 C compiler: gcc (redhat, x86_64, 8.5.0)
 Garbage collector: Serial GC (max heap size: 80% of RAM)
 4 user-specific feature(s):
 - com.oracle.svm.thirdparty.gson.GsonFeature
 - io.quarkus.runner.Feature: Auto-generated class by Quarkus from the existing extensions
 - io.quarkus.runtime.graal.DisableLoggingFeature: Disables INFO logging during the analysis phase
 - org.eclipse.angus.activation.nativeimage.AngusActivationFeature
 
 .......
 
Produced artifacts:
 /code/target/quarkus-camel-native-1.0-SNAPSHOT-native-image-source-jar/build-artifacts.json (build_info)
 /code/target/quarkus-camel-native-1.0-SNAPSHOT-native-image-source-jar/quarkus-camel-native-1.0-SNAPSHOT-runner (executable)
 /code/target/quarkus-camel-native-1.0-SNAPSHOT-native-image-source-jar/quarkus-camel-native-1.0-SNAPSHOT-runner-build-output-stats.json (build_info)
========================================================================================================================
Finished generating 'quarkus-camel-native-1.0-SNAPSHOT-runner' in 3m 24s.

We can gain some benefits from native compilation such as a lighter image and less utilization

$ podman stats -a
ID            NAME               CPU %       MEM USAGE / LIMIT  MEM %       NET IO      BLOCK IO      PIDS        CPU TIME    AVG CPU %
f8745a7b7ce2  gracious_goldberg  0.01%       37.86MB / 4.097GB  0.92%       0B / 0B     0B / 12.29kB  12          1.155723s   0.41%

Code for this activity can be found here,

https://github.com/edwin/quarkus-camel-native

Debugging HTTP Request and Responses in Red Hat Single Sign On

Red Hat Single Sign On (RHSSO) or its opensource project, which is Keycloak, is an open-source software product to allow single sign-on with identity and access management which can be deployed as a cloud service or containerized application. For this sample, we are trying to debug and print all http requests and responses that comes to RHSSO 7.4.6 which is being deployed on Openshift, for debugging purpose. But we also need to be very careful since it will print all http content which might contains sensitive values.

Okay, so lets start with creating a file “sso.cli” which have below content,

/subsystem=undertow/configuration=filter/expression-filter=requestDumperExpression:add(expression="dump-request")
/subsystem=undertow/server=default-server/host=default-host/filter-ref=requestDumperExpression:add

And deploy it as a ConfigMap,

$ oc create configmap jboss-cli --from-file=sso-extensions.cli=sso.cli

Next is mount it as a volume to RHSSO DeploymentConfig

$ oc set volume dc/sso --add --name=jboss-cli \
		-m /opt/eap/extensions -t configmap --configmap-name=jboss-cli \ 
		--default-mode='0755' --overwrite

Rollout the corresponding DeploymentConfig and we can observe that http request-response logs now is showing, we can use this curl command to test

$ curl --location --request POST 'https://sso.url/auth/realms/realm/protocol/openid-connect/userinfo' \
--header 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiw......YXNzPlSVE2Oj0ImIQd6zQkw2UEMiEyJz8FrsVaS7x2M8mQjy-xQrSTGZVXKWR7KLHa-MCRx4S33Ja5nQuD3K_VVihKTyn4cOHnQ'

with below logs as the result

21:46:28,071 INFO  [io.undertow.request.dump] (default task-1) 
----------------------------REQUEST---------------------------
               URI=/auth/realms/realm/protocol/openid-connect/userinfo
 characterEncoding=null
     contentLength=0
       contentType=null
            header=accept=*/*
            header=accept-encoding=gzip, deflate, br
            header=forwarded=for=10.161.5.3;host=sso.url;proto=https
            header=authorization=Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiw......YXNzPlSVE2Oj0ImIQd6zQkw2UEMiEyJz8FrsVaS7x2M8mQjy-xQrSTGZVXKWR7KLHa-MCRx4S33Ja5nQuD3K_VVihKTyn4cOHnQ
            header=x-forwarded-proto=https
            header=x-forwarded-port=443
            header=x-forwarded-for=10.161.5.3
            header=content-length=0
            header=host=sso.url
            header=x-forwarded-host=sso.url
            locale=[]
            method=POST
          protocol=HTTP/1.1
       queryString=
        remoteAddr=/10.161.5.3:0
        remoteHost=10.161.5.3
            scheme=https
              host=sso.url
        serverPort=8443
          isSecure=true
--------------------------RESPONSE--------------------------
     contentLength=73
       contentType=application/json
            header=X-XSS-Protection=1; mode=block
            header=X-Frame-Options=SAMEORIGIN
            header=Referrer-Policy=no-referrer
            header=Date=Wed, 06 Nov 2024 14:46:28 GMT
            header=Connection=keep-alive
            header=WWW-Authenticate=Bearer realm="realm", error="invalid_token", error_description="Token verification failed"
            header=Strict-Transport-Security=max-age=31536000; includeSubDomains
            header=X-Content-Type-Options=nosniff
            header=Content-Type=application/json
            header=Content-Length=73
            status=401

==============================================================

Error “No marshaller registered for object of Java type” in Infinispan

Had this error whenc trying to put a Java bean to Infinispan 15,

java.lang.IllegalArgumentException: No marshaller registered for object of Java type com.edw.model.User : com.edw.model.User@1a8d9c94
	at org.infinispan.protostream.impl.SerializationContextImpl.getMarshallerDelegate(SerializationContextImpl.java:517) ~[protostream-5.0.4.Final.jar:5.0.4.Final]
	at org.infinispan.protostream.WrappedMessage.writeCustomObject(WrappedMessage.java:300) ~[protostream-5.0.4.Final.jar:5.0.4.Final]
	at org.infinispan.protostream.WrappedMessage.writeMessage(WrappedMessage.java:250) ~[protostream-5.0.4.Final.jar:5.0.4.Final]
	at org.infinispan.protostream.WrappedMessage.write(WrappedMessage.java:243) ~[protostream-5.0.4.Final.jar:5.0.4.Final]
	at org.infinispan.protostream.ProtobufUtil.toWrappedByteBuffer(ProtobufUtil.java:152) ~[protostream-5.0.4.Final.jar:5.0.4.Final]
	at org.infinispan.commons.marshall.ImmutableProtoStreamMarshaller.objectToBuffer(ImmutableProtoStreamMarshaller.java:55) ~[infinispan-commons-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.commons.marshall.AbstractMarshaller.objectToByteBuffer(AbstractMarshaller.java:70) ~[infinispan-commons-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.marshall.MarshallerUtil.obj2bytes(MarshallerUtil.java:117) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.DataFormat$DataFormatImpl.valueToBytes(DataFormat.java:92) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.DataFormat.valueToBytes(DataFormat.java:211) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.impl.RemoteCacheImpl.valueToBytes(RemoteCacheImpl.java:628) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.impl.RemoteCacheImpl.putAsync(RemoteCacheImpl.java:315) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.impl.RemoteCacheSupport.put(RemoteCacheSupport.java:196) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]
	at org.infinispan.client.hotrod.impl.RemoteCacheSupport.put(RemoteCacheSupport.java:186) ~[infinispan-client-hotrod-15.0.7.Final.jar:15.0.7.Final]

Actually it happen because of my Java bean (com.edw.model.User) doesnt have any marshaller. This is how my configuration files looks like,

@Configuration
public class InfinispanConfiguration {
    @Bean
    public RemoteCacheManager remoteCacheManager() {
        return new RemoteCacheManager(
                new org.infinispan.client.hotrod.configuration.ConfigurationBuilder()
                        .addServers("localhost:11222")
                        .security().authentication().username("admin2").password("password")
                        .clientIntelligence(ClientIntelligence.HASH_DISTRIBUTION_AWARE)
                        .marshaller(ProtoStreamMarshaller.class)
                        .build());
    }
}

And everything works well after i register a marshaller for User bean

@Configuration
public class InfinispanConfiguration {
    @Bean
    public RemoteCacheManager remoteCacheManager() {
        return new RemoteCacheManager(
                new org.infinispan.client.hotrod.configuration.ConfigurationBuilder()
                        .addServers("localhost:11222")
                        .security().authentication().username("admin2").password("password")
                        .clientIntelligence(ClientIntelligence.HASH_DISTRIBUTION_AWARE)
                        .marshaller(ProtoStreamMarshaller.class)
                        .addContextInitializer(new UserIndexSchemaInitializerImpl())
                        .build());
    }
}

Where UserIndexSchemaInitializerImpl is a generated code coming from interface that extending SerializationContextInitializer class.

Full code for this can be found on my Github repository,

https://github.com/edwin/spring-boot-2-and-infinispan-15