From 2efba01683f87961cd3ab71aa16934f6bce56b48 Mon Sep 17 00:00:00 2001 From: Ankit Rathod Date: Mon, 25 May 2026 16:12:22 +0530 Subject: [PATCH] feat: Implement admin session validation in Aviator gRPC client --- .../cli/aviator/grpc/AviatorGrpcClient.java | 14 ++++++++++++++ .../com/fortify/cli/aviator/util/Constants.java | 1 + .../src/main/proto/Application.proto | 7 +++++++ .../cli/cmd/AviatorAdminConfigCreateCommand.java | 14 +++++++++++++- .../admin/helper/AviatorAdminConfigHelper.java | 12 ++++++++++++ .../_common/util/AviatorSignatureUtils.java | 7 +++---- 6 files changed, 50 insertions(+), 5 deletions(-) diff --git a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorGrpcClient.java b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorGrpcClient.java index d3a1b2bf240..7a77271183b 100644 --- a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorGrpcClient.java +++ b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/grpc/AviatorGrpcClient.java @@ -36,6 +36,7 @@ import com.fortify.aviator.application.GetDefaultQuotaRequest; import com.fortify.aviator.application.GetDefaultQuotaResponse; import com.fortify.aviator.application.UpdateApplicationRequest; +import com.fortify.aviator.application.ValidateAdminSessionRequest; import com.fortify.aviator.dastentitlement.DastEntitlement; import com.fortify.aviator.dastentitlement.DastEntitlementServiceGrpc; import com.fortify.aviator.dastentitlement.ListDastEntitlementsByTenantRequest; @@ -214,6 +215,19 @@ public long getDefaultQuota(String token) { return response.getDefaultQuota(); } + public void validateAdminSession(String tenantName, String signature, String message) { + ValidateAdminSessionRequest request = ValidateAdminSessionRequest.newBuilder() + .setTenantName(tenantName) + .setSignature(signature) + .setMessage(message) + .build(); + GrpcUtil.executeGrpcCall( + blockingStub, + ApplicationServiceGrpc.ApplicationServiceBlockingStub::validateAdminSession, + request, + Constants.OP_VALIDATE_ADMIN_SESSION); + } + public List listApplication(String tenantName, String signature, String message) { ApplicationByTenantName request = ApplicationByTenantName.newBuilder().setName(tenantName).setSignature(signature).setMessage(message).build(); ApplicationList applicationList = GrpcUtil.executeGrpcCall(blockingStub, ApplicationServiceGrpc.ApplicationServiceBlockingStub::listApplications, request, Constants.OP_LIST_APPS); diff --git a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/util/Constants.java b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/util/Constants.java index 022defe545b..680cd15fa22 100644 --- a/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/util/Constants.java +++ b/fcli-core/fcli-aviator-common/src/main/java/com/fortify/cli/aviator/util/Constants.java @@ -72,6 +72,7 @@ public class Constants { public static final String OP_DELETE_TOKEN = "deleting token"; public static final String OP_VALIDATE_TOKEN = "validating token"; public static final String OP_VALIDATE_USER_TOKEN = "validating user token"; + public static final String OP_VALIDATE_ADMIN_SESSION = "admin session validation"; public static final String OP_LIST_ENTITLEMENTS = "listing entitlements"; public static final String OP_LIST_DAST_ENTITLEMENTS = "listing DAST entitlements"; public static final String OP_GET_APP_BY_TOKEN = "retrieving application by token"; diff --git a/fcli-core/fcli-aviator-common/src/main/proto/Application.proto b/fcli-core/fcli-aviator-common/src/main/proto/Application.proto index a31497e93ea..84c744890af 100644 --- a/fcli-core/fcli-aviator-common/src/main/proto/Application.proto +++ b/fcli-core/fcli-aviator-common/src/main/proto/Application.proto @@ -53,6 +53,12 @@ message ApplicationByTenantName { string message = 3; } +message ValidateAdminSessionRequest { + string tenantName = 1; + string signature = 2; + string message = 3; +} + message ApplicationList { repeated Application applications = 1; } @@ -83,6 +89,7 @@ service ApplicationService { rpc UpdateApplication(UpdateApplicationRequest) returns (Application) {} rpc AddEntitlement(ApplicationById) returns (Application) {} rpc DeleteApplication(ApplicationById) returns (ApplicationResponseMessage) {} + rpc ValidateAdminSession(ValidateAdminSessionRequest) returns (google.protobuf.Empty) {} rpc ListApplications(ApplicationByTenantName) returns (ApplicationList) {} rpc ListApplicationsByEntitlement(ApplicationById) returns (ApplicationList) {} rpc GetApplicationByToken(GetApplicationByTokenRequest) returns (Application) {} diff --git a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/cli/cmd/AviatorAdminConfigCreateCommand.java b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/cli/cmd/AviatorAdminConfigCreateCommand.java index 689081eab86..d4ed177ca91 100644 --- a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/cli/cmd/AviatorAdminConfigCreateCommand.java +++ b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/cli/cmd/AviatorAdminConfigCreateCommand.java @@ -12,6 +12,9 @@ */ package com.fortify.cli.aviator._common.config.admin.cli.cmd; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.fortify.cli.aviator._common.config.admin.cli.mixin.AviatorAdminConfigCreateOptions; import com.fortify.cli.aviator._common.config.admin.cli.mixin.AviatorAdminConfigNameArgGroup; import com.fortify.cli.aviator._common.config.admin.helper.AviatorAdminConfigDescriptor; @@ -27,6 +30,8 @@ @Command(name = OutputHelperMixins.Create.CMD_NAME, sortOptions = false) public class AviatorAdminConfigCreateCommand extends AbstractSessionLoginCommand { + private static final Logger LOG = LoggerFactory.getLogger(AviatorAdminConfigCreateCommand.class); + @Mixin @Getter private OutputHelperMixins.Create outputHelper; @Getter private AviatorAdminConfigHelper configHelper = AviatorAdminConfigHelper.instance(); @Mixin private AviatorAdminConfigCreateOptions configCreateOptions = new AviatorAdminConfigCreateOptions(); @@ -45,7 +50,14 @@ protected void logoutBeforeNewLogin(String configName, AviatorAdminConfigDescrip @Override protected AviatorAdminConfigDescriptor login(String configName) { String privateKeyContents = configCreateOptions.getPrivateKeyResolver().getPrivateKeyContents(); - return new AviatorAdminConfigDescriptor(configCreateOptions.getAviatorUrl(), configCreateOptions.getTenant(), privateKeyContents); + AviatorAdminConfigDescriptor configDescriptor = new AviatorAdminConfigDescriptor( + configCreateOptions.getAviatorUrl(), + configCreateOptions.getTenant(), + privateKeyContents); + LOG.info("Validating Aviator admin configuration with the Aviator server..."); + configHelper.validateConfig(configDescriptor); + LOG.info("Aviator admin configuration validated successfully."); + return configDescriptor; } @Override diff --git a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/helper/AviatorAdminConfigHelper.java b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/helper/AviatorAdminConfigHelper.java index c2882876ce2..e7039f7e94b 100644 --- a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/helper/AviatorAdminConfigHelper.java +++ b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/config/admin/helper/AviatorAdminConfigHelper.java @@ -12,6 +12,9 @@ */ package com.fortify.cli.aviator._common.config.admin.helper; +import com.fortify.cli.aviator._common.util.AviatorSignatureUtils; +import com.fortify.cli.aviator.grpc.AviatorGrpcClient; +import com.fortify.cli.aviator.grpc.AviatorGrpcClientHelper; import com.fortify.cli.common.session.helper.AbstractSessionHelper; public class AviatorAdminConfigHelper extends AbstractSessionHelper { @@ -34,6 +37,15 @@ protected Class getSessionDescriptorType() { return AviatorAdminConfigDescriptor.class; } + public void validateConfig(AviatorAdminConfigDescriptor configDescriptor) { + try (AviatorGrpcClient client = AviatorGrpcClientHelper.createClient(configDescriptor.getAviatorUrl())) { + String[] messageAndSignature = AviatorSignatureUtils.createMessageAndSignature(configDescriptor, configDescriptor.getTenant()); + String message = messageAndSignature[0]; + String signature = messageAndSignature[1]; + client.validateAdminSession(configDescriptor.getTenant(), signature, message); + } + } + public static final AviatorAdminConfigHelper instance() { return INSTANCE; } diff --git a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/util/AviatorSignatureUtils.java b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/util/AviatorSignatureUtils.java index e42c86006c9..32d9ae10f56 100644 --- a/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/util/AviatorSignatureUtils.java +++ b/fcli-core/fcli-aviator/src/main/java/com/fortify/cli/aviator/_common/util/AviatorSignatureUtils.java @@ -21,15 +21,12 @@ import com.fortify.cli.common.crypto.helper.SignatureHelper; import com.fortify.cli.common.exception.FcliSimpleException; -import lombok.SneakyThrows; - public class AviatorSignatureUtils { public static String createMessage(String... params) { String timestamp = ZonedDateTime.now(ZoneOffset.UTC).format(DateTimeFormatter.ISO_INSTANT); return String.join(";", params) + ";" + timestamp; } - @SneakyThrows public static String createSignature(String message, AviatorAdminConfigDescriptor configDescriptor) { String privateKeyContent = configDescriptor.getPrivateKeyContents(); if (privateKeyContent == null) { @@ -38,7 +35,9 @@ public static String createSignature(String message, AviatorAdminConfigDescripto try { return SignatureHelper.signer(privateKeyContent, (char[]) null).sign(message, StandardCharsets.UTF_8); } catch (Exception e) { - throw new RuntimeException("Failed to generate signature using resolved private key", e); + throw new FcliSimpleException( + "Unable to sign the Aviator admin request with the provided private key. Verify that --private-key points to a valid PEM private key", + e); } }