Extremely Serious

Category: Java (Page 1 of 3)

Understanding Semaphores in Java for Concurrent Programming

In the realm of concurrent programming, managing shared resources among multiple threads is a critical challenge. To address this, synchronization primitives like semaphores play a pivotal role. In Java, the Semaphore class offers a powerful toolset for controlling access to shared resources.

What is a Semaphore?

A semaphore is a synchronization mechanism that regulates access to shared resources by controlling the number of threads that can access them concurrently. It maintains a set of permits, where each thread must acquire a permit before accessing the shared resource. The number of available permits dictates the level of concurrency allowed.

Java's Semaphore Class

In Java, the Semaphore class resides in the java.util.concurrent package and provides methods to acquire and release permits. Let's explore a simple example to grasp the concept:

import java.util.concurrent.Semaphore;

public class SemaphoreExample {
    public static void main(String[] args) {
        Semaphore semaphore = new Semaphore(2); // Initializes with 2 permits

        Runnable task = () -> {
            try {
                semaphore.acquire(); // Acquire a permit
                // Critical section: access shared resource
                System.out.println(Thread.currentThread().getName() + " is accessing the shared resource.");
                Thread.sleep(2000); // Simulating some work
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                semaphore.release(); // Release the permit
            }
        };

        // Create and start multiple threads
        for (int i = 0; i < 5; i++) {
            new Thread(task).start();
        }
    }
}

In this example, the semaphore with two permits ensures that only two threads can access the shared resource concurrently. The acquire() and release() methods facilitate controlled access to the critical section.

Use Cases for Semaphores

Semaphores are particularly useful in scenarios where limited resources need to be shared among multiple threads. Some common use cases include:

  1. Thread Pool Management: Semaphores can regulate the number of threads active in a pool, preventing resource exhaustion.
  2. Database Connection Pools: Controlling access to a limited number of database connections to avoid overwhelming the system.
  3. Printers and I/O Devices: Managing concurrent access to printers or other I/O devices to prevent conflicts.
  4. Producer-Consumer Problem: Coordinating the interaction between producers and consumers to avoid race conditions.

In conclusion, semaphores in Java provide a robust mechanism for coordinating access to shared resources in a concurrent environment. Understanding their operations and use cases is crucial for building scalable and efficient multi-threaded applications.

Exploring ArrayBlockingQueue in Java

Java provides a variety of concurrent data structures to facilitate communication and synchronization between threads. One such class is ArrayBlockingQueue, which is a blocking queue implementation backed by an array. This queue is particularly useful in scenarios where multiple threads need to exchange data in a producer-consumer fashion.

Initialization

To use ArrayBlockingQueue, start by importing the necessary class:

import java.util.concurrent.ArrayBlockingQueue;

Then, initialize the queue with a specified capacity:

ArrayBlockingQueue<Type> queue = new ArrayBlockingQueue<>(capacity);

Replace Type with the type of elements you want to store, and capacity with the maximum number of elements the queue can hold.

Adding and Removing Elements

Adding Elements

  • put(element): Adds an element to the queue. Blocks if the queue is full.
  • offer(element): Adds an element to the queue if space is available, returns true if successful, false otherwise.
  • offer(element, timeout, timeUnit): Adds an element to the queue, waiting for the specified time if necessary for space to be available.

Removing Elements

  • take(): Removes and returns the head of the queue. Blocks if the queue is empty.
  • poll(): Removes and returns the head of the queue, or returns null if the queue is empty.
  • poll(timeout, timeUnit): Removes and returns the head of the queue, waiting for the specified time if the queue is empty.

Example Usage: Producer-Consumer Scenario

Consider a simple example where a producer thread produces messages, and a consumer thread consumes them using ArrayBlockingQueue:

import java.util.concurrent.ArrayBlockingQueue;

public class ProducerConsumerExample {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);

        // Producer thread
        Thread producer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    String message = "Message " + i;
                    queue.put(message);
                    System.out.println("Produced: " + message);
                    Thread.sleep(1000);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // Consumer thread
        Thread consumer = new Thread(() -> {
            try {
                for (int i = 1; i <= 10; i++) {
                    String message = queue.take();
                    System.out.println("Consumed: " + message);
                    Thread.sleep(1500);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        producer.start();
        consumer.start();
    }
}

In this example, the producer and consumer threads interact through the ArrayBlockingQueue, ensuring a smooth exchange of messages while handling blocking situations when the queue is full or empty.

ArrayBlockingQueue serves as a valuable tool in concurrent programming, providing a simple yet effective means of communication and synchronization between threads in Java.

Generating and Validating JWT Tokens in Java using PEM

JSON Web Tokens (JWT) are a popular way to secure communication between parties using digitally signed tokens. In this article, we will explore how to generate and validate JWT tokens in Java using PEM (Privacy Enhanced Mail) files. PEM files are commonly used to store cryptographic keys and certificates.

Generate JWT Token

In this section, we'll walk through how to generate a JWT token in Java using a private key stored in a PEM file.

Setting up the Environment

Before we proceed, make sure you have the following prerequisites:

  1. Java Development Kit (JDK) installed on your system.
  2. A PEM file containing a private key (referred to as <PRIVATE_KEY_PEM>).

Code Implementation

We'll use Java to create a JWT token. Here's the code for generating a JWT token:

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.UUID;

public class GenerateJWTSignedByPEM {

    public static void main(final String ... args) throws Exception {
        // Load the private key and certificate
        final var privateKeyPEM = """
                <PRIVATE_KEY_PEM>              
                """;

        final var privateKey = getPrivateKeyFromPEM(privateKeyPEM);

        // Create JWT claims
        final var subject = "user123";
        final var issuer = "yourapp.com";
        final var expirationTimeMillis = System.currentTimeMillis() + 3600 * 1000; // 1 hour
        final var jwtID = UUID.randomUUID().toString();

        // Build JWT claims
        final var jwtHeader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        final var jwtClaims = "{\"sub\":\"" + subject + "\",\"iss\":\"" + issuer + "\",\"exp\":" + expirationTimeMillis + ",\"jti\":\"" + jwtID + "\"}";

        // Base64Url encode the JWT header and claims
        final var base64UrlHeader = base64UrlEncode(jwtHeader.getBytes());
        final var base64UrlClaims = base64UrlEncode(jwtClaims.getBytes());

        // Combine header and claims with a period separator
        final var headerClaims = base64UrlHeader + "." + base64UrlClaims;

        // Sign the JWT
        final var signature = signWithRSA(headerClaims, privateKey);

        // Combine the JWT components
        final var jwtToken = headerClaims + "." + signature;

        System.out.println("JWT Token: " + jwtToken);
    }

    // Helper function to load a PrivateKey from PEM format
    private static PrivateKey getPrivateKeyFromPEM(String privateKeyPEM) throws Exception {
        privateKeyPEM = privateKeyPEM.replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");

        final var privateKeyBytes = Base64.getDecoder().decode(privateKeyPEM);

        final var keyFactory = KeyFactory.getInstance("RSA");
        final var keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
        return keyFactory.generatePrivate(keySpec);
    }

    // Base64 URL encoding
    private static String base64UrlEncode(final byte[] data) {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
    }

    // Sign the JWT using RSA
    private static String signWithRSA(final String data, final PrivateKey privateKey) throws Exception {
        final var signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        final var signatureBytes = signature.sign();
        return base64UrlEncode(signatureBytes);
    }
}

Here's a breakdown of the code:

  1. We load the private key from the PEM file.
  2. Create JWT claims, including subject, issuer, expiration time, and a unique JWT ID.
  3. Base64Url encode the JWT header and claims.
  4. Combine the header and claims with a period separator.
  5. Sign the JWT using the private key.
  6. Combine all the JWT components to get the final JWT token.

Make sure to replace <PRIVATE_KEY_PEM> with the actual content of your private key PEM file.

Validate JWT Token

In this section, we'll learn how to validate a JWT token using a public certificate stored in a PEM file.

Setting up the Environment

Ensure you have the following prerequisites:

  1. Java Development Kit (JDK) installed on your system.
  2. A PEM file containing a public certificate (referred to as <PUBLIC_CERT_PEM>).
  3. A JWT token you want to validate (referred to as <JWT_TOKEN>).

Code Implementation

We'll use Java to validate a JWT token. Here's the code:

import java.io.ByteArrayInputStream;
import java.security.PublicKey;
import java.security.Signature;
import java.security.cert.X509Certificate;
import java.util.Base64;

public class ValidateJWTSignedByPEM {
    public static void main(final String ... args) throws Exception {

        // The JWT token to validate.
        final var jwtToken = "<JWT_TOKEN>";

        // Load the X.509 certificate
        final var certificatePEM = """
                <PUBLIC_CERT_PEM>              
                """;

        final var certificate = getCertificateFromPEM(certificatePEM);

        // Parse JWT components
        final var jwtParts = jwtToken.split("\\.");
        if (jwtParts.length != 3) {
            System.out.println("Invalid JWT format");
            return;
        }

        // Decode and verify the JWT signature
        final var base64UrlHeader = jwtParts[0];
        final var base64UrlClaims = jwtParts[1];
        final var signature = jwtParts[2];

        // Verify the signature
        if (verifySignature(base64UrlHeader, base64UrlClaims, signature, certificate.getPublicKey())) {
            System.out.println("JWT signature is valid");
        } else {
            System.out.println("JWT signature is invalid");
        }
    }

    private static X509Certificate getCertificateFromPEM(String certificatePEM) throws Exception {
        certificatePEM = certificatePEM.replace("-----BEGIN CERTIFICATE-----", "")
                .replace("-----END CERTIFICATE-----", "")
                .replaceAll("\\s+", "");

        final var certificateBytes = Base64.getDecoder().decode(certificatePEM);

        final var certificateFactory = java.security.cert.CertificateFactory.getInstance("X.509");
        return (X509Certificate) certificateFactory.generateCertificate(new ByteArrayInputStream(certificateBytes));
    }

    private static boolean verifySignature(final String base64UrlHeader, final String base64UrlClaims, final String signature, final PublicKey publicKey) throws Exception {
        final var signedData = base64UrlHeader + "." + base64UrlClaims;
        final var signatureBytes = Base64.getUrlDecoder().decode(signature);

        final var verifier = Signature.getInstance("SHA256withRSA");
        verifier.initVerify(publicKey);
        verifier.update(signedData.getBytes());

        return verifier.verify(signatureBytes);
    }
}

Here's how the code works:

  1. Load the JWT token and public certificate from their respective PEM files.
  2. Parse the JWT token into its components: header, claims, and signature.
  3. Verify the signature by re-signing the header and claims and comparing it with the provided signature.

Replace <PUBLIC_CERT_PEM> and <JWT_TOKEN> with the actual content of your public certificate PEM file and the JWT token you want to validate.

Summary

In this article, we've explored how to generate and validate JWT tokens in Java using PEM files. This approach allows you to secure your applications by creating and verifying digitally signed tokens. Make sure to keep your private keys and certificates secure, as they are crucial for the security of your JWT-based authentication system.

Related Topic

Generating a Self-signed CA Certificate for JSON Web Token (JWT) in Java

Generating and Validating JWT Tokens in Java using Keystore

JWT (JSON Web Tokens) is a compact, URL-safe means of representing claims to be transferred between two parties. In this article, we will walk through how to generate and validate JWT tokens in Java, using a private certificate stored in a keystore. We will provide example Java code for both processes.

Generate JWT Token

Generating a JWT token involves several steps:

  1. Loading the Keystore: You need to load the keystore that contains the private key and certificate. You'll also specify the keystore password and the alias of the certificate in the keystore.
  2. Creating JWT Claims: Define the claims you want to include in the JWT. These can include the subject, issuer, expiration time, and a unique JWT ID (jti).
  3. Base64URL Encoding: Encode the JWT header and claims in base64 URL-safe format. This is a requirement for JWT.
  4. Combining Header and Claims: Combine the base64-encoded header and claims with a period separator.
  5. Signing the JWT: Sign the JWT using RSA with the private key from the keystore.
  6. Combining JWT Components: Combine the header, claims, and signature to create the final JWT token.

Here's the Java code for generating a JWT token:

import java.io.FileInputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.util.Base64;
import java.util.UUID;

public class GenerateJWTSignedByKSCert {

    public static void main(String... args) throws Exception {
        // Load the keystore and retrieve the private key and certificate
        final var keystorePath = "<CERTIFICATE_KEYSTORE>";
        final var keystorePassword = "<KEYSTORE_PASSWORD>";
        final var alias = "<CERTIFICATE_ALIAS>";
        final var keystore = KeyStore.getInstance("JKS");
        keystore.load(new FileInputStream(keystorePath), keystorePassword.toCharArray());
        final var privateKey = (RSAPrivateKey) keystore.getKey(alias, keystorePassword.toCharArray());

        // Sample JWT claims
        final var subject = "user123";
        final var issuer = "yourapp.com";
        final var expirationTimeMillis = System.currentTimeMillis() + 3600 * 1000; // 1 hour
        final var jwtID = UUID.randomUUID().toString();

        // Build JWT claims
        final var jwtHeader = "{\"alg\":\"RS256\",\"typ\":\"JWT\"}";
        final var jwtClaims = "{\"sub\":\"" + subject + "\",\"iss\":\"" + issuer + "\",\"exp\":" + expirationTimeMillis + ",\"jti\":\"" + jwtID + "\"}";

        // Base64Url encode the JWT header and claims
        final var base64UrlHeader = base64UrlEncode(jwtHeader.getBytes());
        final var base64UrlClaims = base64UrlEncode(jwtClaims.getBytes());

        // Combine header and claims with a period separator
        final var headerClaims = base64UrlHeader + "." + base64UrlClaims;

        // Sign the JWT
        final var signature = signWithRSA(headerClaims, privateKey);

        // Combine the JWT components
        final var jwtToken = headerClaims + "." + signature;

        System.out.println("JWT Token: " + jwtToken);
    }

    // Base64 URL encoding
    private static String base64UrlEncode(byte[] data) {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(data);
    }

    // Sign the JWT using RSA
    private static String signWithRSA(String data, RSAPrivateKey privateKey) throws Exception {
        // Perform the RSA signing (e.g., with Signature.getInstance("SHA256withRSA"))
        // and return the base64Url-encoded signature
        final var signature = Signature.getInstance("SHA256withRSA");
        signature.initSign(privateKey);
        signature.update(data.getBytes());
        final var signatureBytes = signature.sign();
        return base64UrlEncode(signatureBytes);
    }
}

Validate JWT Token

Once you have generated a JWT token, you may need to validate it to ensure its integrity. Validation typically involves verifying the token's signature using the corresponding public key from the keystore. Here's the Java code for validating a JWT token:

import java.io.FileInputStream;
import java.security.*;
import java.security.cert.X509Certificate;
import java.util.Base64;

public class ValidateJWTSignedByKSCert {

    public static void main(final String ... args) throws Exception {
        // The JWT token to validate.
        final var jwtToken = "<JWT_TOKEN>";

        // Load the keystore and retrieve the public key
        final var keystorePath = "<CERTIFICATE_KEYSTORE>";
        final var keystorePassword = "<KEYSTORE_PASSWORD>";
        final var alias = "<CERTIFICATE_ALIAS>";
        KeyStore keystore = KeyStore.getInstance("JKS");
        keystore.load(new FileInputStream(keystorePath), keystorePassword.toCharArray());
        final var certificate = (X509Certificate) keystore.getCertificate(alias);

        // Parse JWT components
        final var jwtParts = jwtToken.split("\\.");
        if (jwtParts.length != 3) {
            System.out.println("Invalid JWT format");
            return;
        }

        // Decode and verify the JWT signature
        final var base64UrlHeader = jwtParts[0];
        final var base64UrlClaims = jwtParts[1];
        final var signature = jwtParts[2];

        // Verify the signature
        if (verifySignature(base64UrlHeader, base64UrlClaims, signature, certificate.getPublicKey())) {
            System.out.println("JWT signature is valid");
        } else {
            System.out.println("JWT signature is invalid");
        }
    }

    private static boolean verifySignature(final String base64UrlHeader, final String base64UrlClaims, final String signature, final PublicKey publicKey) throws Exception {
        final var signedData = base64UrlHeader + "." + base64UrlClaims;
        final var signatureBytes = Base64.getUrlDecoder().decode(signature);

        final var verifier = Signature.getInstance("SHA256withRSA");
        verifier.initVerify(publicKey);
        verifier.update(signedData.getBytes());

        return verifier.verify(signatureBytes);
    }
}

Tokens

In both code examples, there are tokens that need to be replaced with specific values:

  • <CERTIFICATE_KEYSTORE>: Replace this with the absolute path of the keystore. It's possible to have separate keystores for the private and public certificates.
  • <KEYSTORE_PASSWORD>: Replace this with the password that corresponds to the keystore.
  • <CERTIFICATE_ALIAS>: Replace this with the alias of the certificate in the keystore.
  • <JWT_TOKEN>: Replace this with the JWT token you want to validate.

By using the provided code and replacing these tokens with the appropriate values, you can generate and validate JWT tokens in Java with ease, using a private certificate stored in a keystore.

Related Topic

Generating a Self-signed CA Certificate for JSON Web Token (JWT) in Java

Showing JVM Flags and Values

Flags

Flag Description
UnlockDiagnosticVMOptions Unlocks the options intended for diagnosing the JVM. By default, this option is disabled and diagnostic options are not available.
PrintFlagsFinal Shows the final flag values that JVM uses.

Usage

java -XX:+UnlockDiagnosticVMOptions -XX:+PrintFlagsFinal -version

The usage of version argument is used to show the java version information instead of the help information.

Mocking Static Method with Mockito

Sample codes for mocking a static with Mockito.

The StringUtil class is a very trivial class that converts the text to all capitalized.

StringUtil class

public final class StringUtil {

    private StringUtil() {}

    public static String upperCase(String text) {
        return text.toUpperCase();
    }
}

Mocking the StringUtil.upperCase method

Stubbing the StringUtil.upperCase method to return test if test is passed as argument.

Dependencies Required

org.junit.jupiter:junit-jupiter-engine:5.8.2
org.mockito:mockito-inline:4.4.0

StringUtilTest class

import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.*;
import static org.junit.jupiter.api.Assertions.*;

public class StringUtilTest {

    @Test
    void staticMethod() {
        try (var utilities = mockStatic(StringUtil.class)) {
            utilities.when(() -> StringUtil.upperCase("test")).thenReturn("test");
            assertEquals("test", StringUtil.upperCase("test"));
        }
    }
}

Java as a Windows service with NSSM

Pre-requisite

Installing a Java Service

  1. Register a java application as a windows service using the following syntax:

    nssm install <SERVICE_NAME> <JAVA_EXECUTABLE> <JAVA_ARGUMENTS>

    Example

    nssm install "JavaService" "${JAVA_HOME}\bin\java.exe" "-jar java-service.jar --spring.profiles.active=dev"
  2. Update the service with application directory using the following syntax:

    nssm set <SERVICE_NAME> AppDirectory <JAR_FILE_DIRECTORY>

    Example

    nssm set "JavaService" AppDirectory "C:\apps"
  3. Update the service with description using the following syntax:

    nssm set <SERVICE_NAME> Description <APP_DESCRIPTION>

    Example

    nssm set "JavaService" Description "A custom java service."

Displaying the NSSM details of the Java Service

Use the following syntax to display the details of the services:

nssm dump <SERVICE_NAME>

Example

nssm dump "JavaService"

Uninstalling a Java Service

Use the following syntax to remove a java service using nssm:

nssm remove <SERVICE_NAME> confirm

confirm parameter here specifies that we don't want to see the gui confirmation.

Example

nssm remove "JavaService" confirm

Generating a Self-signed CA Certificate for JSON Web Token (JWT) in Java

In the world of secure communication and authentication, JSON Web Tokens (JWTs) play a crucial role. They are often used to verify the authenticity of clients and servers, ensuring secure data transmission. In this guide, we will walk you through the steps to generate a self-signed CA certificate for JWTs in Java.

Prerequisites

Before we get started, make sure you have the necessary tools and binaries installed. If you're using Windows, you can download the OpenSSL binaries from slproweb.com.

Step 1: Generate an RSA Private Key

The first step is to generate an RSA private key, which will be used to create the self-signed certificate. Open your terminal or command prompt and run the following command:

openssl genrsa -aes256 -out jwt.private.pem 2048

This command generates an encrypted PEM private key. If you wish to generate a decrypted PEM based on it, you can use the following command:

openssl rsa -in jwt.private.pem -out decrypted.jwt.private.pem

Step 2: Generate a Public Key (Optional)

Generating a public key is optional in the context of creating a self-signed CA certificate for JWTs in Java. However, if you want to generate one, use the following command:

openssl rsa -pubout -in jwt.private.pem -out jwt.public.pem

The public key generation is not used in the Java keystores, but it can be useful for other purposes.

Step 3: Generate a Self-signed CA Certificate

Now, it's time to create the self-signed CA certificate using the private key you generated earlier. This certificate will be valid for one year. Customize the template by replacing the placeholder values with your own information. Run the following command:

openssl req -key jwt.private.pem -new -x509 -sha256 -days 365 -subj "/C=<2_LETTER_COUNTRY_CODE>/ST=<STATE_NAME>/L=<CITY_NAME>/O=<ORGANIZATION_NAME>/OU=<ORGANIZATIONAL_UNIT>/CN=<YOUR_NAME>/emailAddress=<YOUR_EMAIL_ADDR>" -out jwt.cert.pem

Here's a breakdown of the fields you need to replace:

  • <2_LETTER_COUNTRY_CODE>: The two-letter code of your country.
  • <STATE_NAME>: The name of your state.
  • <CITY_NAME>: The name of your city.
  • <ORGANIZATION_NAME>: The name of your organization.
  • <ORGANIZATIONAL_UNIT>: The name of your section in the organization.
  • <YOUR_NAME>: Your full name.
  • <YOUR_EMAIL_ADDR>: Your email address.

For example:

openssl req -key jwt.private.pem -new -x509 -sha256 -days 365 -subj "/C=NZ/ST=Wellington/L=Wellington/O=RnE/OU=IT/CN=Ronaldo Webb/emailAddress=ron@ronella.xyz" -out jwt.cert.pem

Step 4: Generate a PKCS12 File

Now, create a PKCS12 file by combining the generated private key and certificate. Give it the "selfsigned" alias using the following command:

openssl pkcs12 -export -in jwt.cert.pem -inkey jwt.private.pem -out jwt.pfx -name "selfsigned"

Step 5: Store the PKCS12 Content in a Java Keystore

Java applications often use keystores for certificate management. To store the content of the PKCS12 file in a Java keystore, use the following command:

"%JAVA_HOME%\bin\keytool" -importkeystore -destkeystore jwt-ks.jks -deststorepass password -deststoretype PKCS12 -srckeystore jwt.pfx -srcstoretype PKCS12 -srcstorepass password

Replace "%JAVA_HOME%" with the path to your Java installation directory and customize the keystore name and password as needed.

Step 6: Store the Certificate in a Java Truststore

In Java, truststores are used to store certificates that are trusted for secure communication. Store the certificate you generated earlier in a Java truststore with the "selfsigned" alias using the following command:

"%JAVA_HOME%\bin\keytool" -import -file jwt.cert.pem -keystore jwt-ts.jks -storetype PKCS12 -storepass password -alias selfsigned

Again, make sure to adjust the paths, keystore name, password, and alias according to your requirements.

By following these steps, you can generate a self-signed CA certificate for JWTs in Java, ensuring secure authentication and data transmission in your applications.

Related Topics

For further information on working with JWTs in Java, you can explore these related topics.

Generating a Self-signed CA Certificate for Java Keystores

Creating the java keystore and truststore with private key and certificate pair

  1. Download OpenSSL binaries from the following link if you are using windows:

    https://slproweb.com/products/Win32OpenSSL.html

  2. Create an openssl configuration (i.e. openssl.cnf) file using the following template:

    [ req ]
    default_bits        = 2048
    default_keyfile     = privkey.pem
    distinguished_name  = subject
    req_extensions      = req_ext
    x509_extensions     = x509_ext
    string_mask         = utf8only
    
    # The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
    #   Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
    [ subject ]
    countryName         = Country Name (2 letter code)
    countryName_default     = <2_LETTER_COUNTRY_CODE>
    
    stateOrProvinceName     = State or Province Name (full name)
    stateOrProvinceName_default = <STATE_NAME>
    
    localityName            = Locality Name (eg, city)
    localityName_default        = <CITY_NAME>
    
    organizationName         = Organization Name (eg, company)
    organizationName_default    = <ORGANIZATION_NAME>
    
    organizationalUnitName   = Organizational Unit
    organizationalUnitName_default = <ORGANIZATIONAL_UNIT>
    
    # Use a friendly name here because it's presented to the user. The server's DNS
    #   names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
    #   by both IETF and CA/Browser Forums. If you place a DNS name here, then you
    #   must include the DNS name in the SAN too (otherwise, Chrome and others that
    #   strictly follow the CA/Browser Baseline Requirements will fail).
    commonName          = Common Name (e.g. server FQDN or YOUR name)
    commonName_default      = <YOUR_NAME>
    
    emailAddress            = Email Address
    emailAddress_default        = <YOUR_EMAIL_ADDRESS>
    
    # Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
    [ x509_ext ]
    
    subjectKeyIdentifier        = hash
    authorityKeyIdentifier    = keyid,issuer
    
    # You only need digitalSignature below. *If* you don't allow
    #   RSA Key transport (i.e., you use ephemeral cipher suites), then
    #   omit keyEncipherment because that's key transport.
    basicConstraints        = CA:FALSE
    keyUsage            = digitalSignature, keyEncipherment
    subjectAltName          = @alternate_names
    nsComment           = "OpenSSL Generated Certificate"
    
    # RFC 5280, Section 4.2.1.12 makes EKU optional
    #   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
    #   In either case, you probably only need serverAuth.
    # extendedKeyUsage    = serverAuth, clientAuth
    
    # Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
    [ req_ext ]
    
    subjectKeyIdentifier        = hash
    
    basicConstraints        = CA:FALSE
    keyUsage            = digitalSignature, keyEncipherment
    subjectAltName          = @alternate_names
    nsComment           = "OpenSSL Generated Certificate"
    
    # RFC 5280, Section 4.2.1.12 makes EKU optional
    #   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
    #   In either case, you probably only need serverAuth.
    # extendedKeyUsage    = serverAuth, clientAuth
    
    [ alternate_names ]
    
    DNS.1       = <DNS_1>
    
    # Add more DNS by incrementing the DNS.<SUFFIX> like the following.
    # DNS.2       = <DNS_2>
    # DNS.3       = <DNS_3>
    # DNS.4       = <DNS_4>
    
    # Add these if you need them. But usually you don't want them or
    #   need them in production. You may need them for development.
    # DNS.5       = localhost
    # DNS.6       = localhost.localdomain
    
    # IPv6 localhost
    # DNS.8     = ::1
    
    # IP address using the following:
    # IP.1       = 127.0.0.1

    Replace the following fields on the template:

    Field Name Description
    2_LETTER_COUNTRY_CODE The two letter code of your country.
    STATE_NAME The name of your state.
    CITY_NAME The name of your city.
    ORGANIZATION_NAME The name of your organization.
    ORGANIZATIONAL_UNIT The name of your section in the organization.
    YOUR_NAME Your full name.
    YOUR_EMAIL_ADDR Your email address.
    DNS.<INDEX> Your DNS name.

    Example:

    [ req ]
    default_bits        = 2048
    default_keyfile     = privkey.pem
    distinguished_name  = subject
    req_extensions      = req_ext
    x509_extensions     = x509_ext
    string_mask         = utf8only
    
    # The Subject DN can be formed using X501 or RFC 4514 (see RFC 4519 for a description).
    #   Its sort of a mashup. For example, RFC 4514 does not provide emailAddress.
    [ subject ]
    countryName         = Country Name (2 letter code)
    countryName_default     = NZ
    
    stateOrProvinceName     = State or Province Name (full name)
    stateOrProvinceName_default = Wellington
    
    localityName            = Locality Name (eg, city)
    localityName_default        = Wellington
    
    organizationName         = Organization Name (eg, company)
    organizationName_default    = My Organization
    
    organizationalUnitName   = Organizational Unit
    organizationalUnitName_default = IT Department
    
    # Use a friendly name here because it's presented to the user. The server's DNS
    #   names are placed in Subject Alternate Names. Plus, DNS names here is deprecated
    #   by both IETF and CA/Browser Forums. If you place a DNS name here, then you
    #   must include the DNS name in the SAN too (otherwise, Chrome and others that
    #   strictly follow the CA/Browser Baseline Requirements will fail).
    commonName          = Common Name (e.g. server FQDN or YOUR name)
    commonName_default      = Ronaldo Webb
    
    emailAddress            = Email Address
    emailAddress_default        = ron@ronella.xyz
    
    # Section x509_ext is used when generating a self-signed certificate. I.e., openssl req -x509 ...
    [ x509_ext ]
    
    subjectKeyIdentifier        = hash
    authorityKeyIdentifier    = keyid,issuer
    
    # You only need digitalSignature below. *If* you don't allow
    #   RSA Key transport (i.e., you use ephemeral cipher suites), then
    #   omit keyEncipherment because that's key transport.
    basicConstraints        = CA:FALSE
    keyUsage            = digitalSignature, keyEncipherment
    subjectAltName          = @alternate_names
    nsComment           = "OpenSSL Generated Certificate"
    
    # RFC 5280, Section 4.2.1.12 makes EKU optional
    #   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
    #   In either case, you probably only need serverAuth.
    # extendedKeyUsage    = serverAuth, clientAuth
    
    # Section req_ext is used when generating a certificate signing request. I.e., openssl req ...
    [ req_ext ]
    
    subjectKeyIdentifier        = hash
    
    basicConstraints        = CA:FALSE
    keyUsage            = digitalSignature, keyEncipherment
    subjectAltName          = @alternate_names
    nsComment           = "OpenSSL Generated Certificate"
    
    # RFC 5280, Section 4.2.1.12 makes EKU optional
    #   CA/Browser Baseline Requirements, Appendix (B)(3)(G) makes me confused
    #   In either case, you probably only need serverAuth.
    # extendedKeyUsage    = serverAuth, clientAuth
    
    [ alternate_names ]
    
    DNS.1       = www.ronella.xyz
    
    # Add more DNS by incrementing the DNS.<SUFFIX> like the following.
    # DNS.2       = <DNS_2>
    # DNS.3       = <DNS_3>
    # DNS.4       = <DNS_4>
    
    # Add these if you need them. But usually you don't want them or
    #   need them in production. You may need them for development.
    # DNS.5       = localhost
    # DNS.6       = localhost.localdomain
    
    # IPv6 localhost
    # DNS.8     = ::1
    
    # IP address using the following:
    # IP.1       = 127.0.0.1
  3. Save the openssl.cnf on your desired location.

  4. Generate the private key and certificate with 1yr validity using the following command:

    openssl req -config openssl.cnf -new -x509 -sha256 -newkey rsa:2048 -keyout privkey.pem -days 365 -out cert.pem
  5. Generate a pkcs12 file from the generated private key and certificate with the selfsigned alias using the following command:

    openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out cert.pfx -name selfsigned
  6. Store the pfx file to a java keystore using the following command:

    "%JAVA_HOME%\bin\keytool" -importkeystore -destkeystore keystore.jks -deststorepass password -deststoretype PKCS12 -srckeystore cert.pfx -srcstoretype PKCS12 -srcstorepass password
  7. Store the certificate to a java truststore using the following command:

    "%JAVA_HOME%\bin\keytool" -import -file cert.pem -keystore truststore.jks -storetype PKCS12 -storepass password -alias selfsigned

Tomcat 8.5 Service Basic Management

Service Creation

  1. Open a cmd terminal and change the current directory to the following:

    %CATALINA_HOME%\bin

    In this directory you will find the following files:

    • tomcat8.exe
    • tomcat8w.exe
  2. Copy the file tomcat8w.exe to CustomTomcat8w.exe.

    tomcat8w.exe is in the following pattern:

    <SERVICE_NAME>w.exe

    This makes the default service name set to tomcat8. Copying it to CustomTomcat8w.exe makes a service name of CustomTomcat8.

  3. Set the basic properties of the CustomTomcat8 service using the following command:

    tomcat8.exe //IS//CustomTomcat8 --DisplayName="Apache Custom Tomcat 8" --Install="%CATALINA_HOME%\bin\tomcat8.exe" --StartMode=jvm --StopMode=jvm --StartClass=org.apache.catalina.startup.Bootstrap --StartParams=start --StopClass=org.apache.catalina.startup.Bootstrap --StopParams=stop --Description="Apache Custom Tomcat 8 by Ron"
  4. Set the classpath using the following command:

    tomcat8.exe //US//CustomTomcat8 --Classpath="%CATALINA_HOME%\bin\bootstrap.jar;%CATALINA_HOME%\bin\tomcat-juli.jar"
  5. Set the JVM to use using the following command:

    tomcat8.exe //US//CustomTomcat8 --Jvm="%JAVA_HOME%\jre\bin\server\jvm.dll"
  6. Set some JVM options using the following command:

    tomcat8.exe //US//CustomTomcat8 --JvmOptions="-Dcatalina.home=%CATALINA_HOME%;-Dcatalina.base=%CATALINA_HOME%"
  7. Set logging using the following command:

    tomcat8.exe //US//CustomTomcat8 --LogLevel="Info" --LogPrefix="custom_tomcat8_service-" --LogPath="%CATALINA_HOME%\logs" --StdOutput="auto" --StdError="auto" --PidFile="tomcat8.pid"
  8. Set JVM memory using the following command:

    tomcat8.exe //US//CustomTomcat8 --JvmMs=512 --JvmMx=1024

Service Post Creation

  1. Using the file explorer, find the directory specified by your CATALINA_HOME environment variable and add the LOCAL SERVICE group on the security. Also add the permissions Full Control and Modify to it.

    For example if your CATALINA_HOME is pointing to C:\dev\tools\apache-tomcat-8.5.64 directory, expect something like the following as an output:

  2. Using the file explorer, navigate to %CATALINA_HOME%\bin directory and double click the CustomTomcat8w.exe file. Click the Java tab and ensure that the Java Virtual Machine field was correctly set. If not, update it accordingly.

    For example if your JAVA_HOME is pointing to C:\Program Files\Java\jdk1.8.0_271 directory, ensure that the Java Virtual Machine field is pointing to the correct location of the jvm.dll.

Service Execution

  1. Open a cmd terminal and change the current directory to the following:

    %CATALINA_HOME%\bin
  2. Run the CustomTomcat8 service using the following command:

    tomcat8.exe //RS//CustomTomcat8

Service Termination

  1. Open a cmd terminal and change the current directory to the following:

    %CATALINA_HOME%\bin
  2. Stop the CustomTomcat8 service using the following command:

    tomcat8.exe //SS//CustomTomcat8

Service Removal

  1. Open a cmd terminal and change the current directory to the following:

    %CATALINA_HOME%\bin
  2. Remove the CustomTomcat8 service using the following command:

    tomcat8.exe //DS//CustomTomcat8

Windows Services App

After the service creation was completed and without any error, we can also manage the service using the windows services app. Just look for the value of the --DisplayName parameter (i.e. Apache Custom Tomcat 8) when setting the basic properties of the service. This is depicted as follows by the following snapshot:

Reference

« Older posts