Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Resolving Elasticsearch 8.10.2 Compatibility in Spring Boot with Secure Transport Configuration

Tech 1

Upgrading from legacy iterations often results in dependancy mismatches within the classpath. A common scenario involves integrating version 8.x servers where legacy client libraries (like 7.x) cause NoSuchMethodError or class hierarchy issues, such as conflicts loading org.elasticsearch.client.RequestOptions.Builder. To resolve this, ensure the Java client version corresponds correctly with the server runtime.

Maven Configuration

Adjust the dependency versions to match the target environment without hardcoding conflicting jar paths. The client library should be distinct from the core version to avoid runtime crashes.

<dependencies>
    <dependency>
        <groupId>co.elastic.clients</groupId>
        <artifactId>elasticsearch-java</artifactId>
        <version>8.10.2</version>
    </dependency>
    
    <dependency>
        <groupId>org.elasticsearch.plugin</groupId>
        <artifactId>x-pack-sql-jdbc</artifactId>
        <version>8.10.2</version>
    </dependency>

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
</dependencies>

Note: Explicitly setting the client version to match the server major version prevents compatibility exceptions during startup.

Application Properties

Configure connection details including SSL certificate paths and authentication credentials in the YAML configuration file.

spring:
  data:
    elasticsearch:
      connections:
        rest:
          - uris: "https://localhost:9200"
          username: elastic
          password: secure_password
      ssl:
        verification-mode: certificate
      index: app_data_index
      keystore-path: certs/http_ca.crt

Java Client Setup

Define a configuration class to initialize synchronous and asynchronous clients. Handle SSL context generation manually to accommodate self-signed certificates used by the security enabled cluster.

package com.example.config;

import co.elastic.clients.elasticsearch.ElasticsearchAsyncClient;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.ssl.SSLContextBuilder;
import org.elasticsearch.client.RestClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import javax.net.ssl.SSLContext;
import java.security.cert.CertificateFactory;
import java.security.KeyStore;
import java.io.InputStream;

@Configuration
public class ElasticsearchConfiguration {

    private final String certName = "http_ca.crt";
    private final HttpHost httpHost = new HttpHost("localhost", 9200, "https");

    @Bean
    public ElasticsearchTransport transport() throws Exception {
        CredentialsProvider credProv = new BasicCredentialsProvider();
        credProv.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "password"));

        RestClient restClient = RestClient.builder(httpHost)
                .setHttpClientConfigCallback(
                        builder -> builder
                                .setDefaultCredentialsProvider(credProv)
                                .setSSLContext(buildSslContext()))
                .build();

        return new RestClientTransport(restClient, new JacksonJsonpMapper());
    }

    private static SSLContext buildSslContext() throws Exception {
        ClassPathResource resource = new ClassPathResource("http_ca.crt");
        try (InputStream is = resource.getInputStream()) {
            KeyStore trustStore = KeyStore.getInstance("PKCS12");
            trustStore.load(null, null);
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            trustStore.setCertificateEntry("ca", cf.generateCertificate(is));
            return SSLContextBuilder.custom()
                    .loadTrustMaterial(trustStore, null)
                    .build();
        }
    }

    @Bean
    public ElasticsearchClient syncClient(transport) {
        return new ElasticsearchClient(transport);
    }

    @Bean
    public ElasticsearchAsyncClient asyncClient(transport) {
        return new ElasticsearchAsyncClient(transport);
    }
}

Integration Testing

Validate the connection by performing CRUD operations on indices using JUnit tests.

package com.example.test;

import co.elastic.clients.elasticsearch.indices.*;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class IndexOperationTest {

    @Autowired
    private ElasticsearchClient client;

    @Test
    void verifyIndexLifecycle() throws Exception {
        IndicesClient idxCli = client.indices();
        String testIdx = "verify_test";

        boolean exists = idxCli.exists(e -> e.index(testIdx)).value();
        if (exists) {
            idxCli.delete(d -> d.index(testIdx));
        }

        CreateIndexResponse res = idxCli.create(c -> c.index(testIdx));
        System.out.println("Created: " + res.acknowledged());

        GetIndexResponse getRes = idxCli.get(g -> g.index(testIdx));
        System.out.println("Status: " + getRes.get(testIdx).status());

        idxCli.delete(d -> d.index(testIdx));
    }
}

External Database Connectivity

For SQL-based exploration of the document store, enable the trial license to utilize JDBC drivers. Execute the following request to activate full functionality for DBeaver or similar SQL clients.

POST /_license/start_trial?acknowledge=true&pretty

Once activated, configure your IDE database tool to connect using the Elastic JDBC plugin found in the plugins directory.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.