Skip to content
Draft
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
3318922
JWT pre-flight check code
hrishikesh-nalawade Mar 26, 2026
2fafc3c
handling verifyCertificate Scenarios
hrishikesh-nalawade Mar 27, 2026
33a4b1e
config change for publishing SDK
hrishikesh-nalawade Mar 27, 2026
41f8345
adding Java Doc
hrishikesh-nalawade Mar 31, 2026
138c47d
renaming pre-flight-check to zosmf-jwt-check
hrishikesh-nalawade Apr 1, 2026
0b1f196
Added verbose mode (-v) support
hrishikesh-nalawade Apr 1, 2026
5b2d30c
empty response body handling
hrishikesh-nalawade Apr 1, 2026
074a84f
updating --truststore to --truststore-file
hrishikesh-nalawade Apr 2, 2026
ccf7788
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade Apr 2, 2026
9dff1a0
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade Apr 20, 2026
4bb3b8e
safkeyring truststore bug fix
hrishikesh-nalawade Apr 23, 2026
e2d0058
safkeyring truststore bug fix
hrishikesh-nalawade Apr 24, 2026
2088e48
Debug Logs
hrishikesh-nalawade May 13, 2026
577aa54
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade May 13, 2026
fc8c14f
further fix
hrishikesh-nalawade May 13, 2026
83b8c8f
Merge remote-tracking branch 'origin/hrishikesh-nalawade/GH4526/jwt-p…
hrishikesh-nalawade May 13, 2026
2b566bd
further fix
hrishikesh-nalawade May 13, 2026
06dfd59
Revert "further fix"
hrishikesh-nalawade May 21, 2026
2e9ed3a
Revert "further fix"
hrishikesh-nalawade May 21, 2026
b7947a1
Revert "Debug Logs"
hrishikesh-nalawade May 21, 2026
df3f10f
Revert "safkeyring truststore bug fix"
hrishikesh-nalawade May 21, 2026
4ed5b49
debug logs for safkeyring issue
hrishikesh-nalawade May 25, 2026
ab021b3
new protocol handler code
hrishikesh-nalawade May 25, 2026
75ad634
reverting fallback fixes and debug logs
hrishikesh-nalawade May 25, 2026
cb106d8
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade May 25, 2026
246af1a
fallback with diagnostics
hrishikesh-nalawade May 25, 2026
5538f73
Fix after testing fallbacks
hrishikesh-nalawade May 25, 2026
1fe7ac7
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade May 27, 2026
f1a5b2d
Single Preflight check JAR code
hrishikesh-nalawade May 28, 2026
28c83a1
Merge branch 'v3.x.x' into hrishikesh-nalawade/GH4526/jwt-pre-flight-…
hrishikesh-nalawade May 28, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ ext.javaLibraries = [
'apiml-security-common',
'apiml-tomcat-common',
'certificate-analyser',
'zosmf-jwt-check',
'common-service-core',
'security-service-client-spring',
'apiml-sample-extension',
Expand Down
154 changes: 154 additions & 0 deletions certificate-analyser/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
## Certificate validation tool

### Build

From the root of the `api-layer` repository:

```bash
./gradlew :certificate-analyser:build
```

On Windows:

```powershell
.\gradlew :certificate-analyser:build
```

The fat JAR (with all dependencies bundled, including z/OSMF JWT Check) will be generated at:

```
certificate-analyser/build/libs/certificate-analyser-<version>.jar
```

#### Build Architecture

The `certificate-analyser` module produces a **single unified fat JAR** that bundles:

1. All certificate-analyser classes (certificate validation, local/remote handshake, local verification)
2. All `zosmf-jwt-check` classes (z/OSMF JWK endpoint connectivity check)
3. All shared dependencies (picocli)

This is achieved through the following Gradle configuration:

- `certificate-analyser/build.gradle` declares `implementation project(':zosmf-jwt-check')` as a dependency
- The `jar` task uses `from { configurations.runtimeClasspath.collect { ... } }` to bundle all runtime dependencies into the fat JAR
- `zosmf-jwt-check/build.gradle` produces a thin JAR (no `Main-Class` manifest, no fat-jar bundling) that is consumed only as a build dependency
- The `zosmf-jwt-check` module **does not produce a standalone runnable JAR** — its functionality is accessed exclusively through the certificate-analyser JAR via the `--zosmf-jwt-check` CLI flag

### Usage

java -jar certificate-analyser-<version>.jar --help
Expand Down Expand Up @@ -61,3 +96,122 @@ java --add-modules ibm.crypto.zsecurity,ibm.crypto.hdwrcca \
### Possible issues

Keystore/truststore is owned by different user - permission error. Temporarily Change read permission to all.

---

## z/OSMF JWT Check (embedded)

This JAR also includes the **z/OSMF JWT Check** tool, which verifies connectivity to the z/OSMF JWK endpoint (`/jwt/ibm/api/zOSMFBuilder/jwk`). It helps diagnose configuration issues such as incorrect hostnames, unreachable ports, missing certificates, or misconfigured z/OSMF.

To use the z/OSMF JWT check functionality, pass `--zosmf-jwt-check` as the **first** argument. All subsequent arguments are passed to the z/OSMF JWT check tool.

### z/OSMF JWT Check — Help

```bash
java -jar certificate-analyser-<version>.jar --zosmf-jwt-check --help
```

### z/OSMF JWT Check — CLI Flags

#### Required Flags

| Flag | Description | Example |
|------|-------------|---------|
| `--zosmf-host` | Hostname or IP address of the z/OSMF server | `--zosmf-host myzosmf.example.com` |
| `--zosmf-port` | Port number of the z/OSMF server | `--zosmf-port 11443` |

#### Conditionally Required Flags

These flags are required when `--scheme=https` (the default) and `--verify-certificates` is **not** `DISABLED`:

| Flag | Description |
|------|-------------|
| `--truststore-file` | Path to the truststore file containing the z/OSMF CA certificate |
| `--truststore-password` | Password for the truststore. If specified without a value, you will be prompted interactively |

#### Optional Flags

| Flag | Default | Description |
|------|---------|-------------|
| `--scheme` | `https` | Protocol to use: `http` or `https` |
| `--verify-certificates` | `STRICT` | Certificate verification mode: `STRICT`, `NONSTRICT`, or `DISABLED` |
| `--truststore-type` | `PKCS12` | Format of the truststore file (e.g., `PKCS12`, `JKS`, `JCERACFKS`) |
| `--keystore-file` | *(none)* | Path to keystore file (only needed for mutual TLS / client certificate authentication) |
| `--keystore-password` | *(none)* | Password for the keystore. If specified without a value, you will be prompted interactively |
| `--keystore-type` | `PKCS12` | Format of the keystore file |
| `-v`, `--verbose` | | Print the response body from the endpoint |
| `-h`, `--help` | | Display usage help and exit |

### Certificate Verification Modes

- **STRICT** (default) — Full certificate chain validation + hostname verification. Truststore required.
- **NONSTRICT** — Certificate chain validated, hostname verification skipped. Truststore required.
- **DISABLED** — No certificate validation. No truststore required. **Do not use in production.**

### Exit Codes

| Code | Meaning |
|------|---------|
| `0` | **Success** — z/OSMF JWK endpoint is reachable and responding |
| `4` | **Failure** — connection failed, SSL error, endpoint not found, or configuration error |
| `8` | **Help** — help/version was displayed; no check was performed |

### z/OSMF JWT Check — Examples

**Quick test (DISABLED mode — no truststore needed):**

```bash
java -jar certificate-analyser-<version>.jar --zosmf-jwt-check \
--zosmf-host myzosmf.example.com \
--zosmf-port 11443 \
--verify-certificates DISABLED
```

**STRICT mode (full certificate verification):**

```bash
java -jar certificate-analyser-<version>.jar --zosmf-jwt-check \
--zosmf-host myzosmf.example.com \
--zosmf-port 11443 \
--truststore-file /path/to/truststore.p12 \
--truststore-password changeit
```

**NONSTRICT mode (skip hostname check):**

```bash
java -jar certificate-analyser-<version>.jar --zosmf-jwt-check \
--zosmf-host 10.0.0.50 \
--zosmf-port 11443 \
--truststore-file /path/to/truststore.p12 \
--truststore-password password \
--verify-certificates NONSTRICT
```

**HTTP mode (no SSL):**

```bash
java -jar certificate-analyser-<version>.jar --zosmf-jwt-check \
--zosmf-host myzosmf.example.com \
--zosmf-port 80 \
--scheme http
```

### SAF Keyrings (z/OSMF JWT Check)

On z/OS, if you are using SAF keyrings, provide the keyring path in `safkeyring://` format and add the JVM protocol handler:

```bash
java --add-modules ibm.crypto.zsecurity,ibm.crypto.hdwrcca \
-jar certificate-analyser-<version>.jar --zosmf-jwt-check \
--zosmf-host myzosmf.example.com \
--zosmf-port 11443 \
--truststore-file safkeyring://IZUSVR/ZoweKeyring \
--truststore-password password \
--truststore-type JCERACFKS
```

> **Note:** On IBM Java 17/21, the `--add-modules` flag resolves the IBM crypto modules,
> making the safkeyring URL protocol handler classes accessible. The tool also sets
> `java.protocol.handler.pkgs` internally to register the handler packages with
> the `URL` class. Both mechanisms work together to enable `safkeyring://` URLs.
2 changes: 2 additions & 0 deletions certificate-analyser/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ plugins {
}

dependencies {
implementation project(':zosmf-jwt-check')
implementation libs.picocli
annotationProcessor libs.picocli.codegen

Expand All @@ -16,6 +17,7 @@ compileJava {
}

jar {
dependsOn ':zosmf-jwt-check:jar'
manifest {
attributes(
'Main-Class': 'org.zowe.apiml.Analyser'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,22 @@
import picocli.CommandLine;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SuppressWarnings("squid:S106") //ignoring the System.out System.err warnings
public class Analyser {

private static final String ZOSMF_JWT_CHECK_FLAG = "--zosmf-jwt-check";

public static int mainWithExitCode(String[] args) {
ensureSafkeyringHandler();

if (args.length > 0 && ZOSMF_JWT_CHECK_FLAG.equals(args[0])) {
String[] remainingArgs = Arrays.copyOfRange(args, 1, args.length);
return ZosmfJwtCheck.mainWithExitCode(remainingArgs);
}

try {
ApimlConf conf = new ApimlConf();
CommandLine cmd = new CommandLine(conf);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ void whenHelpRequested_thenHelpIsPrintedAndExitCodeIs8() {
assertTrue(outputStream.toString().contains("Display a help message"));
}

@Test
void whenZosmfJwtCheckFlagPassed_thenDelegatesToZosmfJwtCheck() {
String[] args = {"--zosmf-jwt-check", "--help"};
assertEquals(8, Analyser.mainWithExitCode(args));
assertTrue(outputStream.toString().contains("z/OSMF JWT Check"));
}

@Test
void whenZosmfJwtCheckFlagWithNoArgs_thenReturnsExitCode4() {
String[] args = {"--zosmf-jwt-check"};
assertEquals(4, Analyser.mainWithExitCode(args));
}

@Test
void whenNoRemoteUrlProvided_thenMessageIsPrinted() {
String[] args = {};
Expand Down Expand Up @@ -149,4 +162,4 @@ void whenCalledViaMainWithExitCode_thenPropertyIsSet() {
assertTrue(value.contains("com.ibm.crypto.hdwrCCA.provider"));
}
}
}
}
1 change: 1 addition & 0 deletions gradle/publish.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ext.javaLibraries = [
'apiml-security-common',
'apiml-tomcat-common',
'certificate-analyser',
'zosmf-jwt-check',
'common-service-core',
'security-service-client-spring',
'apiml-sample-extension',
Expand Down
1 change: 1 addition & 0 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ include 'onboarding-enabler-python'
include 'zaas-client'
include 'mock-services'
include 'certificate-analyser'
include 'zosmf-jwt-check'
include 'apiml-tomcat-common'
include 'apiml-sample-extension'
include 'apiml-sample-extension-package'
Expand Down
Loading
Loading