Ayza Documentation

repository·master·Indexed 20 days ago

https://github.com/hakky54/ayza

A security-focused library for Java, Kotlin, and Scala designed to simplify SSL/TLS configuration, certificate management, and validation. Ayza provides fluent APIs for managing keystores and truststores, supports hot reloading of certificates without application restarts, and offers compatibility with over 40 HTTP clients, including Netty, Jetty, and Apache. It includes utilities for handling PEM files, OCSP revocation checking, and custom hostname verification.

Tokens
13.5K
Snippets
32
Records
39
Agent score
20%

What's inside Ayza

  1. Introduction to Ayza

    master

    Ayza is a utility library designed to simplify SSL/TLS configuration for HTTP Clients and Servers in Java, Kotlin, and Scala. It abstracts away the complex and verbose process of configuring SSLContext, KeyManager, and TrustManager objects.

    Key Features

    • Simplified Configuration: Create SSLContext by providing only identity and trust materials, without needing low-level knowledge of TrustManagerFactory or KeyManagerFactory.
    • Hot Reloading: Rotate certificates and SSL materials without restarting or recreating your HTTP Client or Server.
    • Multiple Materials: Support for loading multiple identities, trust stores, key managers, or trust managers.
    • Advanced Security: Support for encrypted PEM files and trusting additional certificates at runtime.
    • Broad Compatibility: Provides materials compatible with over 40 different HTTP clients.

    Compatibility Matrix

    RuntimeSupported Versions
    Java8+
    Kotlin1.5+
    Scala2.11+
    Android24+
  2. Ayza Compatibility and Requirements

    master

    Ayza is designed for high compatibility across the JVM ecosystem. Ensure your environment meets the following requirements:

    • JDK: Compatible with JDK 8 and above.
    • Kotlin: Compatible with Kotlin 1.5 and above.
    • Scala: Compatible with Scala 2.11 and above.
    • Android: Compatible with Android API level 24 and above.
    • License: Apache 2.0
  3. Core SSL Concepts in Ayza

    master

    To use Ayza effectively, it is helpful to understand how it categorizes SSL materials:

    • Identity material: A KeyStore or KeyManager that holds the key pair (both the private and public key).
    • Trust material: A KeyStore or TrustManager containing one or more certificates (public keys). This represents the list of certificates that the application trusts.
    • One-way authentication (One-way TLS/SSL): An HTTPS connection where the client validates the certificate of the server.
    • Two-way authentication (Two-way TLS/SSL / Mutual Authentication): An HTTPS connection where both the client and the server validate each other's certificates.
  4. Swap SSL material at runtime using dummy materials

    master

    You can initialize an SSLFactory with dummy identity and trust materials and then swap them at runtime using SSLUtils.reload(baseSslFactory, updatedSslFactory). This is useful for scenarios where you need to update credentials without recreating the entire client infrastructure.

    // 1. Create base factory with dummies
    SSLFactory baseSslFactory = SSLFactory.builder()
              .withDummyIdentityMaterial()
              .withDummyTrustMaterial()
              .withSwappableIdentityMaterial()
              .withSwappableTrustMaterial()
              .build();
    
    // 2. Use in client
    HttpClient httpClient = HttpClient.newBuilder()
              .sslParameters(baseSslFactory.getSslParameters())
              .sslContext(baseSslFactory.getSslContext())
              .build();
    
    // 3. Reload with real material later
    Runnable sslUpdater = () -> {
        SSLFactory updatedSslFactory = SSLFactory.builder()
              .withIdentityMaterial(Paths.get("/path/to/your/identity.jks"), "password".toCharArray())
              .withTrustMaterial(Paths.get("/path/to/your/truststore.jks"), "password".toCharArray())
              .build();
        SSLUtils.reload(baseSslFactory, updatedSslFactory);
    };
    
    sslUpdater.run();
  5. Reload SSL identity and trust material at runtime

    master

    To update SSL certificates without restarting your application, use a 'swappable' setup.

    1. Build an initial SSLFactory using .withDummyIdentityMaterial(), .withDummyTrustMaterial(), .withSwappableIdentityMaterial(), and .withSwappableTrustMaterial().
    2. Use SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory) to apply new material.
    3. To force existing connections to perform a new handshake immediately, use SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory, true) (default behavior).
    4. To allow existing connections to continue using their current SSL session until it expires, use SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory, false).

    This approach prevents downtime associated with traditional application restarts.

    SSLFactory baseSslFactory = SSLFactory.builder()
              .withDummyIdentityMaterial()
              .withDummyTrustMaterial()
              .withSwappableIdentityMaterial()
              .withSwappableTrustMaterial()
              .build();
    
    HttpClient httpClient = HttpClient.newBuilder()
              .sslParameters(baseSslFactory.getSslParameters())
              .sslContext(baseSslFactory.getSslContext())
              .build();
    
    Runnable sslUpdater = () -> {
        SSLFactory updatedSslFactory = SSLFactory.builder()
              .withIdentityMaterial(Paths.get("/path/to/your/identity.jks"), "password".toCharArray())
              .withTrustMaterial(Paths.get("/path/to/your/truststore.jks"), "password".toCharArray())
              .build();
    
        SSLFactoryUtils.reload(baseSslFactory, updatedSslFactory);
    };
    
    // Initial run to replace dummies
    sslUpdater.run();
    
    // Schedule periodic updates
    Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(sslUpdater, 1, 1, TimeUnit.HOURS);
  6. Trust additional certificates at runtime

    master

    If you want to add new trusted certificates without reloading the entire trust material (e.g., keeping existing system/custom truststores intact), use the 'inflatable' trust material feature.

    Option 1: In-memory addition Use .withInflatableTrustMaterial() and then call TrustManagerUtils.addCertificate to add new X509Certificate objects.

    Option 2: Persistent file-based addition Use .withInflatableTrustMaterial(Path, char[], String, Consumer<TrustManagerParameters>). This allows you to specify a file where new certificates will be stored. If the file exists, it appends to it. The consumer allows you to implement a predicate (e.g., for user confirmation in a GUI) to decide whether to trust the new certificate.

    // Option 1: In-memory
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()
            .withSystemTrustMaterial()
            .withInflatableTrustMaterial()
            .build();
    
    List<X509Certificate> certificates = ... 
    TrustManagerUtils.addCertificate(sslFactory.getTrustManager().get(), certificates);
    
    // Option 2: Persistent file-based
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()
            .withSystemTrustMaterial()
            .withInflatableTrustMaterial(Paths.get("/path/to/truststore.p12"), "password".toCharArray(), "PKCS12", trustManagerParameters -> {
                // Validation logic (e.g., GUI prompt)
                return true;
            })
            .build();
  7. Integrate Ayza with Netty (e.g., Spring WebFlux WebClient)

    master

    To use Ayza with Netty-based clients like Spring WebFlux WebClient, use the ayza-for-netty artifact. This provides NettySslUtils to convert an SSLFactory into a Netty SslContext.

    <dependency>
        <groupId>io.github.hakky54</groupId>
        <artifactId>ayza-for-netty</artifactId>
        <version>10.0.6</version>
    </dependency>
    import io.netty.handler.ssl.SslContext;
    import nl.altindag.ssl.SSLFactory;
    import nl.altindag.ssl.netty.util.NettySslUtils;
    import org.springframework.http.client.reactive.ReactorClientHttpConnector;
    import org.springframework.web.reactive.function.client.WebClient;
    import reactor.netty.http.client.HttpClient;
    
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()
            .build();
    
    SslContext sslContext = NettySslUtils.forClient(sslFactory).build();
    
    HttpClient httpClient = HttpClient.create()
            .secure(sslSpec -> sslSpec.sslContext(sslContext));
    
    WebClient webClient = WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(httpClient))
            .build();
  8. Install Ayza library

    master

    Ayza can be installed using various dependency management tools. Use the following configurations depending on your build system:

    Maven

    Add the following dependency to your pom.xml:

    Gradle

    Add the following to your build.gradle:

    Gradle Kotlin DSL

    Add the following to your build.gradle.kts:

    Scala SBT

    Add the following to your build.sbt:

    Apache Ivy

    Add the following to your ivy.xml:

    <!-- Maven -->
    <dependency>
        <groupId>io.github.hakky54</groupId>
        <artifactId>ayza</artifactId>
        <version>10.0.6</version>
    </dependency>
    
    <!-- Gradle -->
    implementation 'io.github.hakky54:ayza:10.0.6'
    
    <!-- Gradle Kotlin DSL -->
    implementation("io.github.hakky54:ayza:10.0.6")
    
    <!-- Scala SBT -->
    libraryDependencies += "io.github.hakky54" % "ayza" % "10.0.6"
    
    <!-- Apache Ivy -->
    <dependency org="io.github.hakky54" name="ayza" rev="10.0.6"/>
  9. Override global SSL configuration

    master

    If you cannot modify the SSL configuration of a specific server or client (e.g., because it uses default settings), you can force the entire JVM to use a custom SSLContext constructed by SSLFactory. This involves inserting a custom Provider at the highest priority and setting the default SSLContext. This approach ensures that any call to SSLContext.getInstance("TLS") or other standard protocols (SSL, SSLv2, SSLv3, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3) uses your configured factory.

    Note: The SSLFactory used below is an example; replace it with your own initialized instance.

    // The SSLFactory below is just an example, use your own custom initialized one here
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()
            .withSystemTrustMaterial()
            .build();
    
    Provider provider = ProviderUtils.create(sslFactory);
    Security.insertProviderAt(provider, 1);
    SSLContext.setDefault(sslFactory.getSslContext());
  10. Learn Mutual TLS and SSL setup via Mutual-tls-ssl

    master

    For comprehensive tutorials on setting up secure communication scenarios, refer to the Mutual-tls-ssl project. It provides step-by-step instructions for:

    • No security
    • One way authentication
    • Two way authentication
    • Two way authentication with trusting the Certificate Authority

    Additionally, the project covers the creation and implementation of:

    • KeyStores
    • Certificates
    • Certificate Signing Requests (CSRs)
  11. Integrate Ayza with Apache HttpClient 5

    master

    For Apache HttpClient 5, use ayza-for-apache5 to map an SSLFactory to a TlsStrategy, which can be used within a PoolingAsyncClientConnectionManager.

    <dependency>
        <groupId>io.github.hakky54</groupId>
        <artifactId>ayza-for-apache5</artifactId>
        <version>10.0.6</version>
    </dependency>
    import nl.altindag.ssl.SSLFactory;
    import nl.altindag.ssl.apache5.util.Apache5SslUtils;
    import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
    import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
    import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManager;
    import org.apache.hc.client5.http.impl.nio.PoolingAsyncClientConnectionManagerBuilder;
    
    SSLFactory sslFactory = SSLFactory.builder()
            .withDefaultTrustMaterial()
            .build();
    
    PoolingAsyncClientConnectionManager connectionManager = PoolingAsyncClientConnectionManagerBuilder.create()
            .setTlsStrategy(Apache5SslUtils.toTlsStrategy(sslFactory))
            .build();
    
    CloseableHttpAsyncClient httpAsyncClient = HttpAsyncClients.custom()
            .setConnectionManager(connectionManager)
            .build();
    
    httpAsyncClient.start();
  12. Migrate from JVM System Properties to SSLFactory

    master

    If your application currently relies on classic JVM SSL system properties (like -Djavax.net.ssl.trustStore), you can migrate to SSLFactory by using the withSystemPropertyDerived... methods. This allows you to bridge existing configurations into the Ayza model.

    SSLFactory sslFactory = SSLFactory.builder()
            .withSystemPropertyDerivedIdentityMaterial()
            .withSystemPropertyDerivedTrustMaterial()
            .withSystemPropertyDerivedProtocols()
            .withSystemPropertyDerivedCiphers()
            .build();
    
    SSLContext.setDefault(sslFactory.getSslContext());