This is an automated email from the ASF dual-hosted git repository.

lahirujayathilake pushed a commit to branch custos-signer
in repository https://gitbox.apache.org/repos/asf/airavata-custos.git

commit 9527c863fa80f038dbb183808920a68a30506771
Author: lahiruj <[email protected]>
AuthorDate: Wed Dec 10 15:03:27 2025 -0500

    generate test JWT tokens for testing
---
 signer/signer-sdk-core/pom.xml                     |   5 +
 .../signer/sdk/SshClientIntegrationTest.java       |  12 ++-
 .../signer/sdk/util/TestJwtTokenGenerator.java     | 104 +++++++++++++++++++++
 .../signer/service/ca/SshCertificateSigner.java    |   2 +-
 4 files changed, 118 insertions(+), 5 deletions(-)

diff --git a/signer/signer-sdk-core/pom.xml b/signer/signer-sdk-core/pom.xml
index 4bfbad373..adac60b1e 100644
--- a/signer/signer-sdk-core/pom.xml
+++ b/signer/signer-sdk-core/pom.xml
@@ -94,6 +94,11 @@
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.nimbusds</groupId>
+            <artifactId>nimbus-jose-jwt</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git 
a/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/SshClientIntegrationTest.java
 
b/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/SshClientIntegrationTest.java
index 1bb6b70b2..a29ee118f 100644
--- 
a/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/SshClientIntegrationTest.java
+++ 
b/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/SshClientIntegrationTest.java
@@ -20,6 +20,7 @@ package org.apache.custos.signer.sdk;
 import org.apache.custos.signer.sdk.config.SdkConfiguration;
 import org.apache.custos.signer.sdk.keystore.InMemoryKeyStore;
 import org.apache.custos.signer.sdk.keystore.KeyStoreProvider;
+import org.apache.custos.signer.sdk.util.TestJwtTokenGenerator;
 import org.apache.custos.signer.service.policy.KeyType;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
@@ -58,11 +59,14 @@ public class SshClientIntegrationTest {
         try {
             System.out.println("Requesting certificate materials (this will 
auto-generate CA key if first time) using keyType=" + keyType);
 
+            // Generate a valid JWT token for testing
+            String userToken = 
TestJwtTokenGenerator.generateTestToken("exouser");
+
             CertificateMaterials materials = 
client.requestCertificateMaterials(
                     "test-client",  // client alias
                     "exouser",    // principal (SSH username)
                     3600,          // TTL: 1 hour
-                    "test-token",  // user token (for now, just a placeholder 
TODO)
+                    userToken,     // user token (valid JWT for testing)
                     keyType
             );
 
@@ -74,7 +78,7 @@ public class SshClientIntegrationTest {
             assertNotNull(materials.certBytes(), "Certificate bytes should not 
be null");
             assertTrue(Objects.requireNonNull(materials.certBytes()).length > 
0, "Certificate bytes should not be empty");
 
-            System.out.println("✓ Certificate materials received 
successfully!");
+            System.out.println("Certificate materials received successfully!");
             System.out.println("  Serial Number: " + materials.serial());
             System.out.println("  CA Fingerprint: " + 
materials.caFingerprint());
             System.out.println("  Target: " + materials.targetHost() + ":" + 
materials.targetPort());
@@ -87,8 +91,8 @@ public class SshClientIntegrationTest {
             String certContent = materials.opensshCert().trim();
             Files.write(Paths.get(certFile), certContent.getBytes());
 
-            System.out.println("✓ Saved private key to: " + keyFile);
-            System.out.println("✓ Saved certificate to: " + certFile);
+            System.out.println("Saved private key to: " + keyFile);
+            System.out.println("Saved certificate to: " + certFile);
             System.out.println("\nNext steps:");
             System.out.println("1. Extract CA public key from Vault:");
             System.out.println("   vault kv get -field=public_key 
ssh-ca/nexus/test-client/current > /tmp/ca.pub");
diff --git 
a/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/util/TestJwtTokenGenerator.java
 
b/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/util/TestJwtTokenGenerator.java
new file mode 100644
index 000000000..2a9a87421
--- /dev/null
+++ 
b/signer/signer-sdk-core/src/test/java/org/apache/custos/signer/sdk/util/TestJwtTokenGenerator.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the specific language
+ * governing permissions and limitations under the License.
+ */
+package org.apache.custos.signer.sdk.util;
+
+import com.nimbusds.jose.JOSEException;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.JWSHeader;
+import com.nimbusds.jose.JWSSigner;
+import com.nimbusds.jose.JWSVerifier;
+import com.nimbusds.jose.crypto.MACSigner;
+import com.nimbusds.jose.crypto.MACVerifier;
+import com.nimbusds.jwt.JWTClaimsSet;
+import com.nimbusds.jwt.SignedJWT;
+
+import java.time.Instant;
+import java.util.Date;
+
+/**
+ * Utility class for generating test JWT tokens for integration tests.
+ */
+public class TestJwtTokenGenerator {
+
+    // Shared secret for signing (for testing only)
+    private static final String TEST_SECRET = 
"test-secret-key-for-jwt-signing-in-integration-tests-only";
+
+    /**
+     * Generate a test JWT token with the specified principal.
+     *
+     * @param principal The principal (username) to include in the token
+     * @return A signed JWT token string
+     */
+    public static String generateTestToken(String principal) {
+        return generateTestToken(principal, "custos-test-issuer", 3600);
+    }
+
+    /**
+     * Generate a test JWT token with custom claims.
+     *
+     * @param principal  The principal (username) to include in the token
+     * @param issuer     The issuer to include in the token
+     * @param ttlSeconds Token TTL in seconds
+     * @return A signed JWT token string
+     */
+    public static String generateTestToken(String principal, String issuer, 
int ttlSeconds) {
+        try {
+            Instant now = Instant.now();
+            Instant expiry = now.plusSeconds(ttlSeconds);
+
+            JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
+                    .subject(principal)
+                    .issuer(issuer)
+                    .claim("preferred_username", principal)
+                    .claim("email", principal + "@test.example.com")
+                    .claim("sub", principal)
+                    .issueTime(Date.from(now))
+                    .expirationTime(Date.from(expiry))
+                    .jwtID(java.util.UUID.randomUUID().toString())
+                    .build();
+
+            JWSHeader header = new JWSHeader(JWSAlgorithm.HS256);
+            SignedJWT signedJWT = new SignedJWT(header, claimsSet);
+
+            JWSSigner signer = new MACSigner(TEST_SECRET);
+            signedJWT.sign(signer);
+
+            return signedJWT.serialize();
+
+        } catch (JOSEException e) {
+            throw new RuntimeException("Failed to generate test JWT token", e);
+        }
+    }
+
+    /**
+     * Verify a test JWT token (for testing the generator itself).
+     *
+     * @param token The JWT token to verify
+     * @return true if the token is valid
+     */
+    public static boolean verifyTestToken(String token) {
+        try {
+            SignedJWT signedJWT = SignedJWT.parse(token);
+            JWSVerifier verifier = new MACVerifier(TEST_SECRET);
+            return signedJWT.verify(verifier);
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}
+
diff --git 
a/signer/signer-service/src/main/java/org/apache/custos/signer/service/ca/SshCertificateSigner.java
 
b/signer/signer-service/src/main/java/org/apache/custos/signer/service/ca/SshCertificateSigner.java
index 548f027b6..c054dfd7d 100644
--- 
a/signer/signer-service/src/main/java/org/apache/custos/signer/service/ca/SshCertificateSigner.java
+++ 
b/signer/signer-service/src/main/java/org/apache/custos/signer/service/ca/SshCertificateSigner.java
@@ -119,7 +119,7 @@ public class SshCertificateSigner {
         } catch (Exception e) {
             logger.error("Failed to sign SSH certificate for tenant: {}, 
client: {}, principal: {}",
                     tenantId, clientId, principal, e);
-            throw new RuntimeException("Failed to sign SSH certificate", e);
+            throw new RuntimeException("Failed to sign SSH certificate: " + 
e.getMessage(), e);
         }
     }
 

Reply via email to