pzampino commented on code in PR #1291:
URL: https://github.com/apache/knox/pull/1291#discussion_r3538535417


##########
gateway-server/src/main/java/org/apache/knox/gateway/config/impl/GatewayConfigImpl.java:
##########
@@ -818,6 +818,45 @@ public String getHttpClientTruststorePasswordAlias() {
     return get(HTTP_CLIENT_TRUSTSTORE_PASSWORD_ALIAS, 
DEFAULT_HTTP_CLIENT_TRUSTSTORE_PASSWORD_ALIAS);
   }
 
+  @Override
+  public String getHttpClientKeystorePath() {
+    return get(HTTP_CLIENT_KEYSTORE_PATH);
+  }
+
+  @Override
+  public String getHttpClientKeystoreType() {
+    return get(HTTP_CLIENT_KEYSTORE_TYPE, DEFAULT_HTTP_CLIENT_KEYSTORE_TYPE);
+  }
+
+  @Override
+  public String getHttpClientKeystorePasswordAlias() {
+    return get(HTTP_CLIENT_KEYSTORE_PASSWORD_ALIAS, 
DEFAULT_HTTP_CLIENT_KEYSTORE_PASSWORD_ALIAS);
+  }
+
+  @Override
+  public String getHttpClientKeyAlias() {
+    return get(HTTP_CLIENT_KEY_ALIAS, DEFAULT_HTTP_CLIENT_KEY_ALIAS);
+  }
+
+  @Override
+  public String getHttpClientKeyPassphraseAlias() {
+    return get(HTTP_CLIENT_KEY_PASSPHRASE_ALIAS, 
DEFAULT_HTTP_CLIENT_KEY_PASSPHRASE_ALIAS);
+  }
+
+  @Override
+  public boolean isSingleEkuEnabled() {
+    return getBoolean(TLS_SINGLE_EKU_ENABLED, DEFAULT_TLS_SINGLE_EKU_ENABLED);
+  }
+
+  @Override
+  public boolean isHttpClientTwoWaySslEnabled() {
+    String configured = get(HTTP_CLIENT_TWO_WAY_SSL_ENABLED);
+    if (configured != null) {
+      return Boolean.parseBoolean(configured);

Review Comment:
   I believe parseBoolean returns false for null, so I think you could 
eliminate the null check unless this method intends to fall back to 
isSingleEkuEnabled() IFF two-way SSL is NOT explicitly configured. Is that the 
intent here? If so, this only applies to HTTP clients employed by Knox?



##########
gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java:
##########
@@ -132,6 +141,116 @@ private void logAndValidateCertificate(GatewayConfig 
config) throws ServiceLifec
     }
   }
 
+  // Package private for unit test access.
+  // When single-EKU mode is enabled, refuse to start unless:
+  //   - the outbound client-identity keystore is present and holds a usable 
key entry,
+  //   - inbound client authentication is enforced (server truststore + 
client-auth),
+  //   - the outbound HTTP client truststore is configured, and
+  //   - both identities are single-purpose: the client identity carries 
clientAuth (not serverAuth)
+  //     and the server identity carries serverAuth (not clientAuth).
+  // Fail closed: never fall back to the server identity certificate for 
outbound calls, and never
+  // defer a cross-wired/dual-purpose certificate to a runtime handshake 
failure.
+  void validateSingleEkuConfig(GatewayConfig config) throws 
ServiceLifecycleException {
+    // 1. Outbound client-identity keystore must be configured and contain the 
configured key entry.
+    String clientKeystorePath = config.getHttpClientKeystorePath();
+    if (clientKeystorePath == null || clientKeystorePath.isEmpty()) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled (" + 
GatewayConfig.TLS_SINGLE_EKU_ENABLED
+          + "=true) but the HTTP client keystore path (" + 
GatewayConfig.HTTP_CLIENT_KEYSTORE_PATH
+          + ") is not configured. Server will not start.");
+    }
+    String clientKeyAlias = config.getHttpClientKeyAlias();
+    KeyStore clientKeystore;
+    try {
+      clientKeystore = keystoreService.getKeystoreForHttpClient();
+      if (clientKeystore == null || 
!clientKeystore.isKeyEntry(clientKeyAlias)) {
+        throw new ServiceLifecycleException("Single-EKU mode is enabled but 
the HTTP client keystore at "
+            + clientKeystorePath + " does not contain a key entry for alias '" 
+ clientKeyAlias
+            + "' (" + GatewayConfig.HTTP_CLIENT_KEY_ALIAS + "). Server will 
not start.");
+      }
+    } catch (KeystoreServiceException | KeyStoreException e) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled but the 
HTTP client keystore at "
+          + clientKeystorePath + " could not be loaded. Server will not 
start.", e);
+    }
+
+    // 2. Inbound client authentication must be enforced (server truststore + 
client-auth).
+    if (config.getTruststorePath() == null) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled but the 
server truststore ("

Review Comment:
   Again, is it not permissible to have single-purpose certs enabled for Knox 
without assuming/requireing two-way SSL?



##########
gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java:
##########
@@ -132,6 +141,116 @@ private void logAndValidateCertificate(GatewayConfig 
config) throws ServiceLifec
     }
   }
 
+  // Package private for unit test access.
+  // When single-EKU mode is enabled, refuse to start unless:
+  //   - the outbound client-identity keystore is present and holds a usable 
key entry,
+  //   - inbound client authentication is enforced (server truststore + 
client-auth),
+  //   - the outbound HTTP client truststore is configured, and
+  //   - both identities are single-purpose: the client identity carries 
clientAuth (not serverAuth)
+  //     and the server identity carries serverAuth (not clientAuth).
+  // Fail closed: never fall back to the server identity certificate for 
outbound calls, and never
+  // defer a cross-wired/dual-purpose certificate to a runtime handshake 
failure.
+  void validateSingleEkuConfig(GatewayConfig config) throws 
ServiceLifecycleException {
+    // 1. Outbound client-identity keystore must be configured and contain the 
configured key entry.
+    String clientKeystorePath = config.getHttpClientKeystorePath();
+    if (clientKeystorePath == null || clientKeystorePath.isEmpty()) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled (" + 
GatewayConfig.TLS_SINGLE_EKU_ENABLED
+          + "=true) but the HTTP client keystore path (" + 
GatewayConfig.HTTP_CLIENT_KEYSTORE_PATH
+          + ") is not configured. Server will not start.");
+    }
+    String clientKeyAlias = config.getHttpClientKeyAlias();
+    KeyStore clientKeystore;
+    try {
+      clientKeystore = keystoreService.getKeystoreForHttpClient();
+      if (clientKeystore == null || 
!clientKeystore.isKeyEntry(clientKeyAlias)) {
+        throw new ServiceLifecycleException("Single-EKU mode is enabled but 
the HTTP client keystore at "
+            + clientKeystorePath + " does not contain a key entry for alias '" 
+ clientKeyAlias
+            + "' (" + GatewayConfig.HTTP_CLIENT_KEY_ALIAS + "). Server will 
not start.");
+      }
+    } catch (KeystoreServiceException | KeyStoreException e) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled but the 
HTTP client keystore at "
+          + clientKeystorePath + " could not be loaded. Server will not 
start.", e);
+    }
+
+    // 2. Inbound client authentication must be enforced (server truststore + 
client-auth).
+    if (config.getTruststorePath() == null) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled but the 
server truststore ("
+          + GatewayConfig.GATEWAY_TRUSTSTORE_PATH + ") is not configured. 
Server will not start.");
+    }
+    if (!config.isClientAuthNeeded() && !config.isClientAuthWanted()) {

Review Comment:
   Here too it seems two-way SSL is required just because single-purpose certs 
are enabled.



##########
gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/JettySSLService.java:
##########
@@ -132,6 +141,116 @@ private void logAndValidateCertificate(GatewayConfig 
config) throws ServiceLifec
     }
   }
 
+  // Package private for unit test access.
+  // When single-EKU mode is enabled, refuse to start unless:
+  //   - the outbound client-identity keystore is present and holds a usable 
key entry,
+  //   - inbound client authentication is enforced (server truststore + 
client-auth),
+  //   - the outbound HTTP client truststore is configured, and
+  //   - both identities are single-purpose: the client identity carries 
clientAuth (not serverAuth)
+  //     and the server identity carries serverAuth (not clientAuth).
+  // Fail closed: never fall back to the server identity certificate for 
outbound calls, and never
+  // defer a cross-wired/dual-purpose certificate to a runtime handshake 
failure.
+  void validateSingleEkuConfig(GatewayConfig config) throws 
ServiceLifecycleException {
+    // 1. Outbound client-identity keystore must be configured and contain the 
configured key entry.
+    String clientKeystorePath = config.getHttpClientKeystorePath();
+    if (clientKeystorePath == null || clientKeystorePath.isEmpty()) {
+      throw new ServiceLifecycleException("Single-EKU mode is enabled (" + 
GatewayConfig.TLS_SINGLE_EKU_ENABLED

Review Comment:
   Is it not valid to have single-purpose certs enabled WITHOUT two-way SSL, 
thus not requiring the client identity keystore?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to