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); } }
