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

hanicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/knox.git


The following commit(s) were added to refs/heads/master by this push:
     new 9c000de37 KNOX-3316: Change downloaded keystore format based on FIPS 
(#1292)
9c000de37 is described below

commit 9c000de3747fd9db626b6a930ac0fac6450cab05
Author: hanicz <[email protected]>
AuthorDate: Thu Jul 2 10:56:31 2026 +0200

    KNOX-3316: Change downloaded keystore format based on FIPS (#1292)
---
 .../service/metadata/GeneralProxyInformation.java  |  66 ++++++++++++++
 .../service/metadata/KnoxMetadataResource.java     | 100 +++++++++++++--------
 .../general.proxy.information.component.html       |   2 +-
 .../general.proxy.information.component.ts         |   7 ++
 .../home/app/model/general.proxy.information.ts    |   1 +
 5 files changed, 138 insertions(+), 38 deletions(-)

diff --git 
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/GeneralProxyInformation.java
 
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/GeneralProxyInformation.java
index 833f0d341..d15603a69 100644
--- 
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/GeneralProxyInformation.java
+++ 
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/GeneralProxyInformation.java
@@ -55,6 +55,10 @@ public class GeneralProxyInformation {
   @ApiModelProperty(value = "A boolean flag indicating whether Webshell UI 
should be enabled on the Knox Home page")
   private String enableWebshell = "false";
 
+  @XmlElement
+  @ApiModelProperty(value = "The truststore type the homepage should offer for 
download (e.g. 'jks' or 'bcfks')")
+  private String truststoreType = "jks";
+
   public String getVersion() {
     return version;
   }
@@ -112,4 +116,66 @@ public class GeneralProxyInformation {
     this.enableWebshell = enableWebshell;
   }
 
+  public String getTruststoreType() {
+    return truststoreType;
+  }
+
+  public void setTruststoreType(String truststoreType) {
+    this.truststoreType = truststoreType;
+  }
+
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  public static final class Builder {
+    private final GeneralProxyInformation instance = new 
GeneralProxyInformation();
+
+    private Builder() {}
+
+    public Builder version(String version) {
+      instance.setVersion(version);
+      return this;
+    }
+
+    public Builder hostname(String hostname) {
+      instance.setHostname(hostname);
+      return this;
+    }
+
+    public Builder adminUiUrl(String adminUiUrl) {
+      instance.setAdminUiUrl(adminUiUrl);
+      return this;
+    }
+
+    public Builder webShellUrl(String webShellUrl) {
+      instance.setWebShellUrl(webShellUrl);
+      return this;
+    }
+
+    public Builder adminApiBookUrl(String adminApiBookUrl) {
+      instance.setAdminApiBookUrl(adminApiBookUrl);
+      return this;
+    }
+
+    public Builder enableTokenManagement(boolean enableTokenManagement) {
+      
instance.setEnableTokenManagement(Boolean.toString(enableTokenManagement));
+      return this;
+    }
+
+    public Builder enableWebshell(boolean enableWebshell) {
+      instance.setEnableWebshell(Boolean.toString(enableWebshell));
+      return this;
+    }
+
+    public Builder truststoreType(String truststoreType) {
+      instance.setTruststoreType(truststoreType);
+      return this;
+    }
+
+    public GeneralProxyInformation build() {
+      return instance;
+    }
+  }
+
 }
diff --git 
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
 
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
index ba77c0e5d..23e61a9f3 100644
--- 
a/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
+++ 
b/gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java
@@ -54,6 +54,7 @@ import javax.ws.rs.core.Response.Status;
 
 import org.apache.knox.gateway.config.GatewayConfig;
 import org.apache.knox.gateway.dto.HomePageProfile;
+import org.apache.knox.gateway.fips.FipsUtils;
 import org.apache.knox.gateway.i18n.messages.MessagesFactory;
 import org.apache.knox.gateway.service.definition.Metadata;
 import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
@@ -98,39 +99,49 @@ public class KnoxMetadataResource {
   @Produces({ APPLICATION_JSON, APPLICATION_XML })
   @Path("info")
   public GeneralProxyInformation getGeneralProxyInformation() {
-    final GeneralProxyInformation proxyInfo = new GeneralProxyInformation();
     final GatewayServices gatewayServices = (GatewayServices) 
request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
-    if (gatewayServices != null) {
-      final ServerInfoService serviceInfoService = 
gatewayServices.getService(ServiceType.SERVER_INFO_SERVICE);
-      final String versionInfo = serviceInfoService.getBuildVersion() + " 
(hash=" + serviceInfoService.getBuildHash() + ")";
-      proxyInfo.setVersion(versionInfo);
-      proxyInfo.setHostname(Hostname.getHostname());
-      proxyInfo.setAdminApiBookUrl(
-          String.format(Locale.ROOT, 
"https://knox.apache.org/books/knox-%s/user-guide.html#Admin+API";, 
getAdminApiBookVersion(serviceInfoService.getBuildVersion())));
-      final GatewayConfig config = (GatewayConfig) 
request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
-      proxyInfo.setAdminUiUrl(getBaseGatewayUrl(config) + 
"/manager/admin-ui/");
-      proxyInfo.setWebShellUrl(getBaseGatewayUrl(config) + 
"/homepage/webshell-ui/index.html");
-      setTokenManagementEnabledFlag(proxyInfo, gatewayServices);
-      proxyInfo.setEnableWebshell(String.valueOf(config.isWebShellEnabled()));
+    if (gatewayServices == null) {
+      return GeneralProxyInformation.builder().build();
     }
+    final GatewayConfig config = (GatewayConfig) 
request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
+    final ServerInfoService serverInfo = 
gatewayServices.getService(ServiceType.SERVER_INFO_SERVICE);
+    final String baseGatewayUrl = getBaseGatewayUrl(config);
 
-    return proxyInfo;
+    return GeneralProxyInformation.builder()
+        .version(serverInfo.getBuildVersion() + " (hash=" + 
serverInfo.getBuildHash() + ")")
+        .hostname(Hostname.getHostname())
+        .adminUiUrl(baseGatewayUrl + "/manager/admin-ui/")
+        .webShellUrl(baseGatewayUrl + "/homepage/webshell-ui/index.html")
+        .adminApiBookUrl(buildAdminApiBookUrl(serverInfo.getBuildVersion()))
+        .enableTokenManagement(isTokenManagementEnabled(gatewayServices))
+        .enableWebshell(config.isWebShellEnabled())
+        .truststoreType(preferredTruststoreType())
+        .build();
   }
 
-  private void setTokenManagementEnabledFlag(final GeneralProxyInformation 
proxyInfo, final GatewayServices gatewayServices) {
+  private boolean isTokenManagementEnabled(final GatewayServices 
gatewayServices) {
     try {
       final AliasService aliasService = 
gatewayServices.getService(ServiceType.ALIAS_SERVICE);
       final List<String> aliases = 
aliasService.getAliasesForCluster(AliasService.NO_CLUSTER_NAME);
       final boolean tokenManagementEnabled = 
aliases.contains(TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME);
-      
proxyInfo.setEnableTokenManagement(Boolean.toString(tokenManagementEnabled));
       if (!tokenManagementEnabled) {
         LOG.tokenManagementDisabled();
       }
+      return tokenManagementEnabled;
     } catch (AliasServiceException e) {
       LOG.failedToFetchGatewayAliasList(e.getMessage(), e);
+      return false;
     }
   }
 
+  private String buildAdminApiBookUrl(String buildVersion) {
+    return String.format(Locale.ROOT, 
"https://knox.apache.org/books/knox-%s/user-guide.html#Admin+API";, 
getAdminApiBookVersion(buildVersion));
+  }
+
+  private String preferredTruststoreType() {
+    return FipsUtils.isFipsEnabledWithBCProvider() ? "bcfks" : "jks";
+  }
+
   private String getAdminApiBookVersion(String buildVersion) {
     return buildVersion.replaceAll(SNAPSHOT_VERSION_POSTFIX, 
"").replaceAll("\\.", "-");
   }
@@ -142,18 +153,21 @@ public class KnoxMetadataResource {
     final GatewayConfig config = (GatewayConfig) 
request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
     final Certificate[] certificateChain = config.isSSLEnabled() ? 
getPublicCertificates() : getSigningkeyCerts(config);
     if (certificateChain != null) {
+      final java.nio.file.Path certFilePath;
       if ("pem".equals(certType)) {
-        generateCertificatePem(certificateChain, config);
-        return generateSuccessFileDownloadResponse(pemFilePath);
+        certFilePath = generateCertificatePem(certificateChain, config);
       } else if ("jks".equals(certType)) {
-        generateCertificateJks(certificateChain, config);
-        return generateSuccessFileDownloadResponse(jksFilePath);
+        certFilePath = generateCertificateJks(certificateChain, config);
       } else if ("bcfks".equals(certType)) {
-        generateCertificateBcfks(certificateChain, config);
-        return generateSuccessFileDownloadResponse(bcfksFilePath);
+        certFilePath = generateCertificateBcfks(certificateChain, config);
       } else {
         return generateFailureFileDownloadResponse(Status.BAD_REQUEST, 
"Invalid certification type provided!");
       }
+      if (certFilePath != null && certFilePath.toFile().exists()) {
+        return generateSuccessFileDownloadResponse(certFilePath);
+      }
+      return generateFailureFileDownloadResponse(Status.SERVICE_UNAVAILABLE,
+          "Could not generate " + certType.toUpperCase(Locale.ROOT) + " public 
certificate");
     }
     return generateFailureFileDownloadResponse(Status.SERVICE_UNAVAILABLE, 
"Could not generate public certificate");
   }
@@ -190,36 +204,48 @@ public class KnoxMetadataResource {
     return null;
   }
 
-  private void generateCertificatePem(Certificate[] certificateChain, 
GatewayConfig gatewayConfig) {
+  private java.nio.file.Path generateCertificatePem(Certificate[] 
certificateChain, GatewayConfig gatewayConfig) {
+    if (pemFilePath != null && pemFilePath.toFile().exists()) {
+      return pemFilePath;
+    }
+    final java.nio.file.Path candidate = 
Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.pem");
     try {
-      if (pemFilePath == null || !pemFilePath.toFile().exists()) {
-        pemFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), 
"gateway-client-trust.pem");
-        X509CertificateUtil.writeCertificatesToFile(certificateChain, 
pemFilePath.toFile());
-      }
+      X509CertificateUtil.writeCertificatesToFile(certificateChain, 
candidate.toFile());
+      pemFilePath = candidate;
+      return pemFilePath;
     } catch (CertificateEncodingException | IOException e) {
       LOG.failedToGeneratePublicCert("PEM", e.getMessage(), e);
+      return null;
     }
   }
 
-  private void generateCertificateJks(Certificate[] certificateChain, 
GatewayConfig gatewayConfig) {
+  private java.nio.file.Path generateCertificateJks(Certificate[] 
certificateChain, GatewayConfig gatewayConfig) {
+    if (jksFilePath != null && jksFilePath.toFile().exists()) {
+      return jksFilePath;
+    }
+    final java.nio.file.Path candidate = 
Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.jks");
     try {
-      if (jksFilePath == null || !jksFilePath.toFile().exists()) {
-        jksFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), 
"gateway-client-trust.jks");
-        X509CertificateUtil.writeCertificatesToJks(certificateChain, 
jksFilePath.toFile(), null);
-      }
+      X509CertificateUtil.writeCertificatesToJks(certificateChain, 
candidate.toFile(), null);
+      jksFilePath = candidate;
+      return jksFilePath;
     } catch (IOException | KeyStoreException | NoSuchAlgorithmException | 
CertificateException e) {
       LOG.failedToGeneratePublicCert("JKS", e.getMessage(), e);
+      return null;
     }
   }
 
-  private void generateCertificateBcfks(Certificate[] certificateChain, 
GatewayConfig gatewayConfig) {
+  private java.nio.file.Path generateCertificateBcfks(Certificate[] 
certificateChain, GatewayConfig gatewayConfig) {
+    if (bcfksFilePath != null && bcfksFilePath.toFile().exists()) {
+      return bcfksFilePath;
+    }
+    final java.nio.file.Path candidate = 
Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.bcfks");
     try {
-      if (bcfksFilePath == null || !bcfksFilePath.toFile().exists()) {
-        bcfksFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), 
"gateway-client-trust.bcfks");
-        X509CertificateUtil.writeCertificatesToBcfks(certificateChain, 
bcfksFilePath.toFile(), null);
-      }
+      X509CertificateUtil.writeCertificatesToBcfks(certificateChain, 
candidate.toFile(), null);
+      bcfksFilePath = candidate;
+      return bcfksFilePath;
     } catch (IOException | KeyStoreException | NoSuchAlgorithmException | 
CertificateException e) {
       LOG.failedToGeneratePublicCert("BCFKS", e.getMessage(), e);
+      return null;
     }
   }
 
diff --git 
a/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.html
 
b/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.html
index fb3b097ce..1cef2a53c 100644
--- 
a/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.html
+++ 
b/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.html
@@ -49,7 +49,7 @@ limitations under the License.
           <td>
             <a href="{{ getMetadataAPIUrl('publicCert?type=pem') }}">PEM</a>
             &nbsp;&nbsp;|&nbsp;&nbsp;
-            <a href="{{ getMetadataAPIUrl('publicCert?type=jks') }}">JKS</a>
+            <a href="{{ getMetadataAPIUrl('publicCert?type=' + 
getTruststoreType()) }}">{{ getTruststoreType().toUpperCase() }}</a>
           </td>
         </tr>
       }
diff --git 
a/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.ts
 
b/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.ts
index 9bba05fc0..d2d7ce5c0 100644
--- 
a/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.ts
+++ 
b/knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.ts
@@ -111,6 +111,13 @@ export class GeneralProxyInformationComponent implements 
OnInit {
         return false;
     }
 
+    getTruststoreType() {
+        if (this.generalProxyInformation && 
this.generalProxyInformation.truststoreType) {
+            return this.generalProxyInformation.truststoreType;
+        }
+        return 'jks';
+    }
+
     ngOnInit(): void {
         console.debug('GeneralProxyInformationComponent --> ngOnInit() --> ');
         this.homepageService.getGeneralProxyInformation()
diff --git a/knox-homepage-ui/home/app/model/general.proxy.information.ts 
b/knox-homepage-ui/home/app/model/general.proxy.information.ts
index 3efe82389..0a3184891 100644
--- a/knox-homepage-ui/home/app/model/general.proxy.information.ts
+++ b/knox-homepage-ui/home/app/model/general.proxy.information.ts
@@ -23,4 +23,5 @@ export class GeneralProxyInformation {
     adminApiBookUrl: string;
     enableTokenManagement: string;
     enableWebshell: string;
+    truststoreType: string;
 }

Reply via email to