Skip to content

Commit 157af95

Browse files
haniczsmolnar82
authored andcommitted
KNOX-3316: Change downloaded keystore format based on FIPS (#1292)
(cherry picked from commit 9c000de)
1 parent 1b43be0 commit 157af95

5 files changed

Lines changed: 138 additions & 38 deletions

File tree

gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/GeneralProxyInformation.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ public class GeneralProxyInformation {
5555
@ApiModelProperty(value = "A boolean flag indicating whether Webshell UI should be enabled on the Knox Home page")
5656
private String enableWebshell = "false";
5757

58+
@XmlElement
59+
@ApiModelProperty(value = "The truststore type the homepage should offer for download (e.g. 'jks' or 'bcfks')")
60+
private String truststoreType = "jks";
61+
5862
public String getVersion() {
5963
return version;
6064
}
@@ -112,4 +116,66 @@ public void setEnableWebshell(String enableWebshell) {
112116
this.enableWebshell = enableWebshell;
113117
}
114118

119+
public String getTruststoreType() {
120+
return truststoreType;
121+
}
122+
123+
public void setTruststoreType(String truststoreType) {
124+
this.truststoreType = truststoreType;
125+
}
126+
127+
public static Builder builder() {
128+
return new Builder();
129+
}
130+
131+
public static final class Builder {
132+
private final GeneralProxyInformation instance = new GeneralProxyInformation();
133+
134+
private Builder() {}
135+
136+
public Builder version(String version) {
137+
instance.setVersion(version);
138+
return this;
139+
}
140+
141+
public Builder hostname(String hostname) {
142+
instance.setHostname(hostname);
143+
return this;
144+
}
145+
146+
public Builder adminUiUrl(String adminUiUrl) {
147+
instance.setAdminUiUrl(adminUiUrl);
148+
return this;
149+
}
150+
151+
public Builder webShellUrl(String webShellUrl) {
152+
instance.setWebShellUrl(webShellUrl);
153+
return this;
154+
}
155+
156+
public Builder adminApiBookUrl(String adminApiBookUrl) {
157+
instance.setAdminApiBookUrl(adminApiBookUrl);
158+
return this;
159+
}
160+
161+
public Builder enableTokenManagement(boolean enableTokenManagement) {
162+
instance.setEnableTokenManagement(Boolean.toString(enableTokenManagement));
163+
return this;
164+
}
165+
166+
public Builder enableWebshell(boolean enableWebshell) {
167+
instance.setEnableWebshell(Boolean.toString(enableWebshell));
168+
return this;
169+
}
170+
171+
public Builder truststoreType(String truststoreType) {
172+
instance.setTruststoreType(truststoreType);
173+
return this;
174+
}
175+
176+
public GeneralProxyInformation build() {
177+
return instance;
178+
}
179+
}
180+
115181
}

gateway-service-metadata/src/main/java/org/apache/knox/gateway/service/metadata/KnoxMetadataResource.java

Lines changed: 63 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454

5555
import org.apache.knox.gateway.config.GatewayConfig;
5656
import org.apache.knox.gateway.dto.HomePageProfile;
57+
import org.apache.knox.gateway.fips.FipsUtils;
5758
import org.apache.knox.gateway.i18n.messages.MessagesFactory;
5859
import org.apache.knox.gateway.service.definition.Metadata;
5960
import org.apache.knox.gateway.service.definition.ServiceDefinitionPair;
@@ -98,39 +99,49 @@ public class KnoxMetadataResource {
9899
@Produces({ APPLICATION_JSON, APPLICATION_XML })
99100
@Path("info")
100101
public GeneralProxyInformation getGeneralProxyInformation() {
101-
final GeneralProxyInformation proxyInfo = new GeneralProxyInformation();
102102
final GatewayServices gatewayServices = (GatewayServices) request.getServletContext().getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE);
103-
if (gatewayServices != null) {
104-
final ServerInfoService serviceInfoService = gatewayServices.getService(ServiceType.SERVER_INFO_SERVICE);
105-
final String versionInfo = serviceInfoService.getBuildVersion() + " (hash=" + serviceInfoService.getBuildHash() + ")";
106-
proxyInfo.setVersion(versionInfo);
107-
proxyInfo.setHostname(Hostname.getHostname());
108-
proxyInfo.setAdminApiBookUrl(
109-
String.format(Locale.ROOT, "https://knox.apache.org/books/knox-%s/user-guide.html#Admin+API", getAdminApiBookVersion(serviceInfoService.getBuildVersion())));
110-
final GatewayConfig config = (GatewayConfig) request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
111-
proxyInfo.setAdminUiUrl(getBaseGatewayUrl(config) + "/manager/admin-ui/");
112-
proxyInfo.setWebShellUrl(getBaseGatewayUrl(config) + "/homepage/webshell-ui/index.html");
113-
setTokenManagementEnabledFlag(proxyInfo, gatewayServices);
114-
proxyInfo.setEnableWebshell(String.valueOf(config.isWebShellEnabled()));
103+
if (gatewayServices == null) {
104+
return GeneralProxyInformation.builder().build();
115105
}
106+
final GatewayConfig config = (GatewayConfig) request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
107+
final ServerInfoService serverInfo = gatewayServices.getService(ServiceType.SERVER_INFO_SERVICE);
108+
final String baseGatewayUrl = getBaseGatewayUrl(config);
116109

117-
return proxyInfo;
110+
return GeneralProxyInformation.builder()
111+
.version(serverInfo.getBuildVersion() + " (hash=" + serverInfo.getBuildHash() + ")")
112+
.hostname(Hostname.getHostname())
113+
.adminUiUrl(baseGatewayUrl + "/manager/admin-ui/")
114+
.webShellUrl(baseGatewayUrl + "/homepage/webshell-ui/index.html")
115+
.adminApiBookUrl(buildAdminApiBookUrl(serverInfo.getBuildVersion()))
116+
.enableTokenManagement(isTokenManagementEnabled(gatewayServices))
117+
.enableWebshell(config.isWebShellEnabled())
118+
.truststoreType(preferredTruststoreType())
119+
.build();
118120
}
119121

120-
private void setTokenManagementEnabledFlag(final GeneralProxyInformation proxyInfo, final GatewayServices gatewayServices) {
122+
private boolean isTokenManagementEnabled(final GatewayServices gatewayServices) {
121123
try {
122124
final AliasService aliasService = gatewayServices.getService(ServiceType.ALIAS_SERVICE);
123125
final List<String> aliases = aliasService.getAliasesForCluster(AliasService.NO_CLUSTER_NAME);
124126
final boolean tokenManagementEnabled = aliases.contains(TokenMAC.KNOX_TOKEN_HASH_KEY_ALIAS_NAME);
125-
proxyInfo.setEnableTokenManagement(Boolean.toString(tokenManagementEnabled));
126127
if (!tokenManagementEnabled) {
127128
LOG.tokenManagementDisabled();
128129
}
130+
return tokenManagementEnabled;
129131
} catch (AliasServiceException e) {
130132
LOG.failedToFetchGatewayAliasList(e.getMessage(), e);
133+
return false;
131134
}
132135
}
133136

137+
private String buildAdminApiBookUrl(String buildVersion) {
138+
return String.format(Locale.ROOT, "https://knox.apache.org/books/knox-%s/user-guide.html#Admin+API", getAdminApiBookVersion(buildVersion));
139+
}
140+
141+
private String preferredTruststoreType() {
142+
return FipsUtils.isFipsEnabledWithBCProvider() ? "bcfks" : "jks";
143+
}
144+
134145
private String getAdminApiBookVersion(String buildVersion) {
135146
return buildVersion.replaceAll(SNAPSHOT_VERSION_POSTFIX, "").replaceAll("\\.", "-");
136147
}
@@ -142,18 +153,21 @@ public Response getPublicCertification(@QueryParam("type") @DefaultValue("pem")
142153
final GatewayConfig config = (GatewayConfig) request.getServletContext().getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE);
143154
final Certificate[] certificateChain = config.isSSLEnabled() ? getPublicCertificates() : getSigningkeyCerts(config);
144155
if (certificateChain != null) {
156+
final java.nio.file.Path certFilePath;
145157
if ("pem".equals(certType)) {
146-
generateCertificatePem(certificateChain, config);
147-
return generateSuccessFileDownloadResponse(pemFilePath);
158+
certFilePath = generateCertificatePem(certificateChain, config);
148159
} else if ("jks".equals(certType)) {
149-
generateCertificateJks(certificateChain, config);
150-
return generateSuccessFileDownloadResponse(jksFilePath);
160+
certFilePath = generateCertificateJks(certificateChain, config);
151161
} else if ("bcfks".equals(certType)) {
152-
generateCertificateBcfks(certificateChain, config);
153-
return generateSuccessFileDownloadResponse(bcfksFilePath);
162+
certFilePath = generateCertificateBcfks(certificateChain, config);
154163
} else {
155164
return generateFailureFileDownloadResponse(Status.BAD_REQUEST, "Invalid certification type provided!");
156165
}
166+
if (certFilePath != null && certFilePath.toFile().exists()) {
167+
return generateSuccessFileDownloadResponse(certFilePath);
168+
}
169+
return generateFailureFileDownloadResponse(Status.SERVICE_UNAVAILABLE,
170+
"Could not generate " + certType.toUpperCase(Locale.ROOT) + " public certificate");
157171
}
158172
return generateFailureFileDownloadResponse(Status.SERVICE_UNAVAILABLE, "Could not generate public certificate");
159173
}
@@ -190,36 +204,48 @@ private Certificate[] getPublicCertificates() {
190204
return null;
191205
}
192206

193-
private void generateCertificatePem(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
207+
private java.nio.file.Path generateCertificatePem(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
208+
if (pemFilePath != null && pemFilePath.toFile().exists()) {
209+
return pemFilePath;
210+
}
211+
final java.nio.file.Path candidate = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.pem");
194212
try {
195-
if (pemFilePath == null || !pemFilePath.toFile().exists()) {
196-
pemFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.pem");
197-
X509CertificateUtil.writeCertificatesToFile(certificateChain, pemFilePath.toFile());
198-
}
213+
X509CertificateUtil.writeCertificatesToFile(certificateChain, candidate.toFile());
214+
pemFilePath = candidate;
215+
return pemFilePath;
199216
} catch (CertificateEncodingException | IOException e) {
200217
LOG.failedToGeneratePublicCert("PEM", e.getMessage(), e);
218+
return null;
201219
}
202220
}
203221

204-
private void generateCertificateJks(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
222+
private java.nio.file.Path generateCertificateJks(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
223+
if (jksFilePath != null && jksFilePath.toFile().exists()) {
224+
return jksFilePath;
225+
}
226+
final java.nio.file.Path candidate = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.jks");
205227
try {
206-
if (jksFilePath == null || !jksFilePath.toFile().exists()) {
207-
jksFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.jks");
208-
X509CertificateUtil.writeCertificatesToJks(certificateChain, jksFilePath.toFile(), null);
209-
}
228+
X509CertificateUtil.writeCertificatesToJks(certificateChain, candidate.toFile(), null);
229+
jksFilePath = candidate;
230+
return jksFilePath;
210231
} catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) {
211232
LOG.failedToGeneratePublicCert("JKS", e.getMessage(), e);
233+
return null;
212234
}
213235
}
214236

215-
private void generateCertificateBcfks(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
237+
private java.nio.file.Path generateCertificateBcfks(Certificate[] certificateChain, GatewayConfig gatewayConfig) {
238+
if (bcfksFilePath != null && bcfksFilePath.toFile().exists()) {
239+
return bcfksFilePath;
240+
}
241+
final java.nio.file.Path candidate = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.bcfks");
216242
try {
217-
if (bcfksFilePath == null || !bcfksFilePath.toFile().exists()) {
218-
bcfksFilePath = Paths.get(gatewayConfig.getGatewaySecurityDir(), "gateway-client-trust.bcfks");
219-
X509CertificateUtil.writeCertificatesToBcfks(certificateChain, bcfksFilePath.toFile(), null);
220-
}
243+
X509CertificateUtil.writeCertificatesToBcfks(certificateChain, candidate.toFile(), null);
244+
bcfksFilePath = candidate;
245+
return bcfksFilePath;
221246
} catch (IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException e) {
222247
LOG.failedToGeneratePublicCert("BCFKS", e.getMessage(), e);
248+
return null;
223249
}
224250
}
225251

knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ <h4 (click)="toggleBoolean('showGeneralProxyInformation')" class="d-flex align-i
4949
<td>
5050
<a href="{{ getMetadataAPIUrl('publicCert?type=pem') }}">PEM</a>
5151
&nbsp;&nbsp;|&nbsp;&nbsp;
52-
<a href="{{ getMetadataAPIUrl('publicCert?type=jks') }}">JKS</a>
52+
<a href="{{ getMetadataAPIUrl('publicCert?type=' + getTruststoreType()) }}">{{ getTruststoreType().toUpperCase() }}</a>
5353
</td>
5454
</tr>
5555
}

knox-homepage-ui/home/app/generalProxyInformation/general.proxy.information.component.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ export class GeneralProxyInformationComponent implements OnInit {
111111
return false;
112112
}
113113

114+
getTruststoreType() {
115+
if (this.generalProxyInformation && this.generalProxyInformation.truststoreType) {
116+
return this.generalProxyInformation.truststoreType;
117+
}
118+
return 'jks';
119+
}
120+
114121
ngOnInit(): void {
115122
console.debug('GeneralProxyInformationComponent --> ngOnInit() --> ');
116123
this.homepageService.getGeneralProxyInformation()

knox-homepage-ui/home/app/model/general.proxy.information.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ export class GeneralProxyInformation {
2323
adminApiBookUrl: string;
2424
enableTokenManagement: string;
2525
enableWebshell: string;
26+
truststoreType: string;
2627
}

0 commit comments

Comments
 (0)