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

lmccay 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 29c606fe4 KNOX-3105 - Add Topology Level Config for Truststore to 
RemoteAuthProvider (#1001)
29c606fe4 is described below

commit 29c606fe4e5a9e423cc48eb0fbebcf2b7b13eeeb
Author: lmccay <[email protected]>
AuthorDate: Tue Mar 4 09:51:20 2025 -0500

    KNOX-3105 - Add Topology Level Config for Truststore to RemoteAuthProvider 
(#1001)
    
    * KNOX-3105 - Add Topology Level Config for Truststore to RemoteAuthProvider
---
 .../knox/gateway/filter/RemoteAuthFilter.java      |  76 +++++++---
 .../knox/gateway/filter/RemoteAuthFilterTest.java  | 165 +++++++++++++++++++--
 .../security/impl/DefaultKeystoreService.java      |  21 +++
 .../gateway/services/security/KeystoreService.java |  22 +++
 4 files changed, 247 insertions(+), 37 deletions(-)

diff --git 
a/gateway-provider-security-authc-remote/src/main/java/org/apache/knox/gateway/filter/RemoteAuthFilter.java
 
b/gateway-provider-security-authc-remote/src/main/java/org/apache/knox/gateway/filter/RemoteAuthFilter.java
index 8932b3873..bbf5d17aa 100755
--- 
a/gateway-provider-security-authc-remote/src/main/java/org/apache/knox/gateway/filter/RemoteAuthFilter.java
+++ 
b/gateway-provider-security-authc-remote/src/main/java/org/apache/knox/gateway/filter/RemoteAuthFilter.java
@@ -63,20 +63,24 @@ import java.util.concurrent.TimeUnit;
 
 public class RemoteAuthFilter implements Filter {
 
-  private static final String CONFIG_REMOTE_AUTH_URL = "remote.auth.url";
-  private static final String CONFIG_INCLUDE_HEADERS = 
"remote.auth.include.headers";
-  private static final String CONFIG_CACHE_KEY_HEADER = 
"remote.auth.cache.key";
-  private static final String CONFIG_EXPIRE_AFTER = "remote.auth.expire.after";
-  private static final String DEFAULT_CACHE_KEY_HEADER = "Authorization";
-  private static final String CONFIG_USER_HEADER = "remote.auth.user.header";
-  private static final String CONFIG_GROUP_HEADER = "remote.auth.group.header";
-  private static final String DEFAULT_CONFIG_USER_HEADER = "X-Knox-Actor-ID";
-  private static final String DEFAULT_CONFIG_GROUP_HEADER = 
"X-Knox-Actor-Groups-*";
-  private static final String WILDCARD = "*";
+  static final String REMOTE_AUTH = "remote.auth.";
+  static final String CONFIG_REMOTE_AUTH_URL = REMOTE_AUTH + "url";
+  static final String CONFIG_INCLUDE_HEADERS = REMOTE_AUTH + "include.headers";
+  static final String CONFIG_CACHE_KEY_HEADER = REMOTE_AUTH + "cache.key";
+  static final String CONFIG_EXPIRE_AFTER = REMOTE_AUTH + "expire.after";
+  static final String DEFAULT_CACHE_KEY_HEADER = "Authorization";
+  static final String CONFIG_USER_HEADER = REMOTE_AUTH + "user.header";
+  static final String CONFIG_GROUP_HEADER = REMOTE_AUTH + "group.header";
+  static final String DEFAULT_CONFIG_USER_HEADER = "X-Knox-Actor-ID";
+  static final String DEFAULT_CONFIG_GROUP_HEADER = "X-Knox-Actor-Groups-*";
+  static final String CONFIG_TRUSTSTORE_PATH = REMOTE_AUTH + "truststore.path";
+  static final String CONFIG_TRUSTSTORE_PASSWORD = REMOTE_AUTH + 
"truststore.password";
+  static final String CONFIG_TRUSTSTORE_TYPE = REMOTE_AUTH + "truststore.type";
+  static final String DEFAULT_TRUSTSTORE_TYPE = "JKS";
+  static final String WILDCARD = "*";
   static final String TRACE_ID = "trace_id";
   static final String REQUEST_ID_HEADER_NAME = "X-Request-Id";
 
-
   private String remoteAuthUrl;
   private List<String> includeHeaders;
   private String cacheKeyHeader;
@@ -94,6 +98,10 @@ public class RemoteAuthFilter implements Filter {
           AuditConstants.DEFAULT_AUDITOR_NAME, 
AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME );
   private final RemoteAuthMessages LOGGER = MessagesFactory.get( 
RemoteAuthMessages.class );
 
+  private String truststorePath;
+  private String truststorePassword;
+  private String truststoreType;
+
   @Override
   public void init(FilterConfig filterConfig) throws ServletException {
     remoteAuthUrl = filterConfig.getInitParameter(CONFIG_REMOTE_AUTH_URL);
@@ -123,6 +131,13 @@ public class RemoteAuthFilter implements Filter {
     } else {
       groupHeaders = Arrays.asList(groupHeaderParam.split("\\s*,\\s*"));
     }
+
+    truststorePath = filterConfig.getInitParameter(CONFIG_TRUSTSTORE_PATH);
+    truststorePassword = 
filterConfig.getInitParameter(CONFIG_TRUSTSTORE_PASSWORD);
+    truststoreType = filterConfig.getInitParameter(CONFIG_TRUSTSTORE_TYPE);
+    if (truststoreType == null || truststoreType.isEmpty()) {
+      truststoreType = DEFAULT_TRUSTSTORE_TYPE;
+    }
   }
 
   public SSLSocketFactory createSSLSocketFactory(KeyStore trustStore) throws 
Exception {
@@ -202,14 +217,7 @@ public class RemoteAuthFilter implements Filter {
     if (services != null) {
       KeystoreService keystoreService = 
services.getService(ServiceType.KEYSTORE_SERVICE);
       if (keystoreService != null) {
-        try {
-          truststore = keystoreService.getTruststoreForHttpClient();
-          if (truststore == null) {
-            truststore = keystoreService.getKeystoreForGateway();
-          }
-        } catch (KeystoreServiceException e) {
-          LOGGER.failedToLoadTruststore(e.getMessage(), e);
-        }
+        truststore = getTrustStore(truststore, keystoreService);
       }
     }
     HttpURLConnection connection;
@@ -217,11 +225,11 @@ public class RemoteAuthFilter implements Filter {
       URL url = new URL(remoteAuthUrl);
       connection = (HttpURLConnection) url.openConnection();
       if (truststore != null) {
-          try {
-              ((HttpsURLConnection) 
connection).setSSLSocketFactory(createSSLSocketFactory(truststore));
-          } catch (Exception e) {
-              throw new RuntimeException(e);
-          }
+        try {
+          ((HttpsURLConnection) 
connection).setSSLSocketFactory(createSSLSocketFactory(truststore));
+        } catch (Exception e) {
+          throw new RuntimeException(e);
+        }
       }
     } else {
       connection = httpURLConnection;
@@ -229,6 +237,26 @@ public class RemoteAuthFilter implements Filter {
     return connection;
   }
 
+  private KeyStore getTrustStore(KeyStore truststore, KeystoreService 
keystoreService) throws IOException {
+    try {
+      // Try topology-specific truststore first if configured
+      if (truststorePath != null && !truststorePath.isEmpty()) {
+        truststore = keystoreService.loadTruststore(truststorePath, 
truststoreType, truststorePassword);
+      }
+      // Fall back to gateway-level truststore
+      if (truststore == null) {
+        truststore = keystoreService.getTruststoreForHttpClient();
+        if (truststore == null) {
+          truststore = keystoreService.getKeystoreForGateway();
+        }
+      }
+    } catch (KeystoreServiceException e) {
+      LOGGER.failedToLoadTruststore(e.getMessage(), e);
+      throw new IOException("Failed to load truststore: ", e);
+    }
+    return truststore;
+  }
+
   private void continueWithEstablishedSecurityContext(Subject subject, final 
HttpServletRequest request, final HttpServletResponse response, final 
FilterChain chain) throws IOException, ServletException {
     try {
       Subject.doAs(
diff --git 
a/gateway-provider-security-authc-remote/src/test/java/org/apache/knox/gateway/filter/RemoteAuthFilterTest.java
 
b/gateway-provider-security-authc-remote/src/test/java/org/apache/knox/gateway/filter/RemoteAuthFilterTest.java
index e31fff451..f81af57e5 100644
--- 
a/gateway-provider-security-authc-remote/src/test/java/org/apache/knox/gateway/filter/RemoteAuthFilterTest.java
+++ 
b/gateway-provider-security-authc-remote/src/test/java/org/apache/knox/gateway/filter/RemoteAuthFilterTest.java
@@ -19,6 +19,10 @@ package org.apache.knox.gateway.filter;
 
 import org.apache.knox.gateway.security.GroupPrincipal;
 import org.apache.knox.gateway.security.PrimaryPrincipal;
+import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
+import org.apache.knox.gateway.services.security.KeystoreService;
+import org.apache.knox.gateway.services.security.KeystoreServiceException;
 import org.apache.knox.test.mock.MockServletContext;
 import org.easymock.EasyMock;
 import org.junit.Before;
@@ -28,6 +32,7 @@ import org.apache.logging.log4j.ThreadContext;
 import javax.security.auth.Subject;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
+import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
@@ -45,17 +50,19 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.security.KeyStore;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+@SuppressWarnings("PMD.JUnit4TestShouldUseBeforeAnnotation")
 public class RemoteAuthFilterTest {
 
     public static final String BEARER_INVALID_TOKEN = "Bearer invalid-token";
     public static final String BEARER_VALID_TOKEN = "Bearer valid-token";
-    public static final String URL_SUCCESS = "http://example.com/auth";;
-    private static final String URL_FAIL = "http://example.com/authfail";;
+    public static final String URL_SUCCESS = "https://example.com/auth";;
+    private static final String URL_FAIL = "https://example.com/authfail";;
     public static final String X_AUTHENTICATED_USER = "X-Authenticated-User";
     public static final String X_AUTHENTICATED_GROUP = "X-Authenticated-Group";
     public static final String X_AUTHENTICATED_GROUP_2 = 
"X-Authenticated-Group-2";
@@ -65,22 +72,52 @@ public class RemoteAuthFilterTest {
     private HttpServletRequest requestMock;
     private HttpServletResponse responseMock;
     private TestFilterChain chainMock;
+    private GatewayServices gatewayServicesMock;
+    private KeystoreService keystoreServiceMock;
+    private ServletContext servletContextMock;
+
     @Before
-    public void setUp() {
-        FilterConfig filterConfigMock = 
EasyMock.createNiceMock(FilterConfig.class);
+    public void createMocks() {
         requestMock = EasyMock.createMock(HttpServletRequest.class);
         responseMock = EasyMock.createMock(HttpServletResponse.class);
+    }
+
+    private void setUp(String trustStorePath, String trustStorePass, String 
trustStoreType) {
+        // Reset existing mocks
+        EasyMock.reset(requestMock, responseMock);
+
+        FilterConfig filterConfigMock = 
EasyMock.createNiceMock(FilterConfig.class);
         chainMock = new TestFilterChain();
 
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.url")).andReturn("http://example.com/auth";).anyTimes();
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.include.headers")).andReturn("Authorization").anyTimes();
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.cache.key")).andReturn("Authorization").anyTimes();
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.expire.after")).andReturn("5").anyTimes();
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.user.header")).andReturn(X_AUTHENTICATED_USER).anyTimes();
-        
EasyMock.expect(filterConfigMock.getInitParameter("remote.auth.group.header"))
+        // Create and configure Gateway Services mocks
+        gatewayServicesMock = EasyMock.createNiceMock(GatewayServices.class);
+        keystoreServiceMock = EasyMock.createNiceMock(KeystoreService.class);
+        servletContextMock = EasyMock.createNiceMock(ServletContext.class);
+
+        // Set up Gateway Services expectations
+        
EasyMock.expect(gatewayServicesMock.getService(ServiceType.KEYSTORE_SERVICE))
+               .andReturn(keystoreServiceMock)
+               .anyTimes();
+        
EasyMock.expect(servletContextMock.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE))
+               .andReturn(gatewayServicesMock)
+               .anyTimes();
+
+        // Basic config
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_REMOTE_AUTH_URL)).andReturn("https://example.com/auth";).anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_INCLUDE_HEADERS)).andReturn("Authorization").anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.DEFAULT_CACHE_KEY_HEADER)).andReturn("Authorization").anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_EXPIRE_AFTER)).andReturn("5").anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_USER_HEADER)).andReturn(X_AUTHENTICATED_USER).anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_GROUP_HEADER))
                .andReturn(X_AUTHENTICATED_GROUP + "," + 
X_AUTHENTICATED_GROUP_2 + ",X-Custom-Group-*").anyTimes();
 
-        EasyMock.replay(filterConfigMock);
+        // Trust store config
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_TRUSTSTORE_PATH)).andReturn(trustStorePath).anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_TRUSTSTORE_PASSWORD)).andReturn(trustStorePass).anyTimes();
+        
EasyMock.expect(filterConfigMock.getInitParameter(RemoteAuthFilter.CONFIG_TRUSTSTORE_TYPE)).andReturn(trustStoreType).anyTimes();
+
+        // Only replay the mocks that won't need additional expectations
+        EasyMock.replay(filterConfigMock, gatewayServicesMock, 
servletContextMock);
 
         filter = new RemoteAuthFilter();
         try {
@@ -90,6 +127,11 @@ public class RemoteAuthFilterTest {
         }
     }
 
+    // Default setup method for backward compatibility
+    private void setUp() {
+        setUp(null, null, null);
+    }
+
     private void setupURLConnection(String url) {
         try {
             filter.httpURLConnection = new MockHttpURLConnection(new URL(url));
@@ -100,6 +142,8 @@ public class RemoteAuthFilterTest {
 
     @Test
     public void successfulAuthentication() throws Exception {
+        setUp();
+
         EasyMock.expect(requestMock.getServletContext()).andReturn(new 
MockServletContext()).anyTimes();
         
EasyMock.expect(requestMock.getHeader("Authorization")).andReturn(BEARER_VALID_TOKEN).anyTimes();
         EasyMock.expect(responseMock.getStatus()).andReturn(200).anyTimes();
@@ -134,6 +178,8 @@ public class RemoteAuthFilterTest {
 
     @Test
     public void authenticationFailsWithInvalidToken() throws Exception {
+        setUp();
+
         EasyMock.expect(requestMock.getServletContext()).andReturn(new 
MockServletContext()).anyTimes();
         EasyMock.expect(responseMock.getStatus()).andReturn(401).anyTimes();
         
EasyMock.expect(requestMock.getHeader("Authorization")).andReturn(BEARER_INVALID_TOKEN).anyTimes();
@@ -160,11 +206,12 @@ public class RemoteAuthFilterTest {
 
     @Test
     public void testCacheBehavior() throws Exception {
+        setUp();
+
         String principalName = "lmccayiv";
         String groupNames = "admin2,scientists";
         Subject subject = new Subject();
         subject.getPrincipals().add(new PrimaryPrincipal(principalName));
-        // Add groups to the principal if available
         Arrays.stream(groupNames.split(",")).forEach(groupName -> 
subject.getPrincipals()
                 .add(new GroupPrincipal(groupName)));
         filter.setCachedSubject(BEARER_VALID_TOKEN, subject);
@@ -202,9 +249,10 @@ public class RemoteAuthFilterTest {
 
     @Test
     public void testTraceIdPropagation() throws Exception {
+        setUp();
+
         String expectedTraceId = "test-trace-123";
 
-        // Set up mocks
         EasyMock.expect(requestMock.getServletContext())
             .andReturn(new MockServletContext())
             .anyTimes();
@@ -250,6 +298,8 @@ public class RemoteAuthFilterTest {
 
     @Test
     public void successfulAuthenticationWithMultipleGroups() throws Exception {
+        setUp();
+
         EasyMock.expect(requestMock.getServletContext()).andReturn(new 
MockServletContext()).anyTimes();
         
EasyMock.expect(requestMock.getHeader("Authorization")).andReturn(BEARER_VALID_TOKEN).anyTimes();
         EasyMock.expect(responseMock.getStatus()).andReturn(200).anyTimes();
@@ -287,6 +337,95 @@ public class RemoteAuthFilterTest {
         }
     }
 
+    @Test
+    public void testSuccessfulHttpsRequestWithTrustStore() throws Exception {
+        // Setup with valid trust store configuration
+        setUp("/path/to/truststore.jks", "trustpass", "JKS");
+
+        KeyStore testTruststore = KeyStore.getInstance("JKS");
+        
EasyMock.expect(keystoreServiceMock.loadTruststore("/path/to/truststore.jks", 
"JKS", "trustpass"))
+               .andReturn(testTruststore)
+               .anyTimes();
+
+        EasyMock.expect(requestMock.getServletContext())
+               .andReturn(servletContextMock)
+               .anyTimes();
+        EasyMock.expect(requestMock.getHeader("Authorization"))
+               .andReturn(BEARER_VALID_TOKEN)
+               .anyTimes();
+        EasyMock.expect(responseMock.getStatus())
+               .andReturn(200)
+               .anyTimes();
+        
responseMock.sendError(EasyMock.eq(HttpServletResponse.SC_UNAUTHORIZED), 
EasyMock.anyString());
+        EasyMock.expectLastCall().andThrow(new AssertionError("Authentication 
should be successful, but was not.")).anyTimes();
+
+        EasyMock.replay(requestMock, responseMock, keystoreServiceMock);
+
+        setupURLConnection("https://example.com/auth";);
+        filter.doFilter(requestMock, responseMock, chainMock);
+
+        assertTrue("Filter chain should have been called", 
chainMock.doFilterCalled);
+    }
+
+    @Test
+    public void testHttpsRequestWithoutTrustStore() throws Exception {
+        // Setup without trust store configuration
+        setUp(null, null, null);
+
+        KeyStore defaultTruststore = KeyStore.getInstance("JKS");
+        EasyMock.expect(keystoreServiceMock.getTruststoreForHttpClient())
+               .andReturn(defaultTruststore)
+               .anyTimes();
+
+        EasyMock.expect(requestMock.getServletContext())
+               .andReturn(servletContextMock)
+               .anyTimes();
+        EasyMock.expect(requestMock.getHeader("Authorization"))
+               .andReturn(BEARER_VALID_TOKEN)
+               .anyTimes();
+        EasyMock.expect(responseMock.getStatus())
+               .andReturn(200)
+               .anyTimes();
+        
responseMock.sendError(EasyMock.eq(HttpServletResponse.SC_UNAUTHORIZED), 
EasyMock.anyString());
+        EasyMock.expectLastCall().andThrow(new AssertionError("Authentication 
should be successful, but was not.")).anyTimes();
+
+        EasyMock.replay(requestMock, responseMock, keystoreServiceMock);
+
+        setupURLConnection("https://example.com/auth";);
+        filter.doFilter(requestMock, responseMock, chainMock);
+
+        assertTrue("Filter chain should have been called with default trust 
store", chainMock.doFilterCalled);
+    }
+
+    @Test
+    public void testHttpsRequestWithInvalidTrustStoreConfig() throws Exception 
{
+        // Setup with invalid trust store configuration
+        setUp("/nonexistent/path/truststore.jks", "password", "JKS");
+
+        
EasyMock.expect(keystoreServiceMock.loadTruststore("/nonexistent/path/truststore.jks",
 "JKS", "password"))
+               .andThrow(new KeystoreServiceException("Failed to load 
truststore"))
+               .anyTimes();
+
+        EasyMock.expect(requestMock.getServletContext())
+               .andReturn(servletContextMock)
+               .anyTimes();
+        EasyMock.expect(requestMock.getHeader("Authorization"))
+               .andReturn(BEARER_VALID_TOKEN)
+               .anyTimes();
+        EasyMock.expect(responseMock.getStatus())
+               .andReturn(500)
+               .anyTimes();
+        responseMock.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 
"Error processing authentication request");
+        EasyMock.expectLastCall().once();
+
+        EasyMock.replay(requestMock, responseMock, keystoreServiceMock);
+
+        filter.doFilter(requestMock, responseMock, chainMock);
+
+        assertFalse("Filter chain should not have been called", 
chainMock.doFilterCalled);
+        EasyMock.verify(responseMock);
+    }
+
     public static class MockHttpURLConnection extends HttpURLConnection {
         private final URL url;
         private int responseCode;
diff --git 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
index 2ed637a47..e51f904ae 100644
--- 
a/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
+++ 
b/gateway-server/src/main/java/org/apache/knox/gateway/services/security/impl/DefaultKeystoreService.java
@@ -46,6 +46,7 @@ import java.net.InetAddress;
 import java.nio.channels.Channels;
 import java.nio.channels.FileChannel;
 import java.nio.charset.StandardCharsets;
+import java.nio.file.FileSystems;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
@@ -562,6 +563,26 @@ public class DefaultKeystoreService implements 
KeystoreService {
     }
   }
 
+  @Override
+  public synchronized KeyStore loadKeyStore(String path, String keystoreType, 
String password)
+          throws KeystoreServiceException {
+      try {
+          return createKeyStore(FileSystems.getDefault().getPath(path), 
keystoreType, password.toCharArray());
+      } catch (Exception e) {
+          throw new KeystoreServiceException(e);
+      }
+  }
+
+  @Override
+  public synchronized KeyStore loadTruststore(String path,  String 
keystoreType, String password)
+          throws KeystoreServiceException {
+      try {
+          return loadKeyStore(FileSystems.getDefault().getPath(path), 
keystoreType, password.toCharArray());
+      } catch (Exception e) {
+          throw new KeystoreServiceException(e);
+      }
+  }
+
   // Package private for unit test access
   synchronized void writeKeyStoreToFile(final KeyStore keyStore, final Path 
path, char[] password)
       throws KeyStoreException, IOException, NoSuchAlgorithmException, 
CertificateException {
diff --git 
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
 
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
index b2cb717a9..dc8069a86 100644
--- 
a/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
+++ 
b/gateway-spi/src/main/java/org/apache/knox/gateway/services/security/KeystoreService.java
@@ -79,4 +79,26 @@ public interface KeystoreService extends Service {
   char[] getCredentialForCluster(String clusterName, String alias, KeyStore 
ks) throws KeystoreServiceException;
 
   String getKeystorePath();
+
+      /**
+     * Load a keystore from the specified path with the given password.
+     *
+     * @param path The path to the keystore file
+     * @param password The password for the keystore
+     * @return The loaded KeyStore instance
+     * @throws KeystoreServiceException if loading fails
+     */
+    KeyStore loadKeyStore(String path, String keystoreType, String password)
+        throws KeystoreServiceException;
+
+    /**
+     * Load a truststore from the specified path with the given password.
+     *
+     * @param path The path to the truststore file
+     * @param password The password for the truststore
+     * @return The loaded KeyStore instance
+     * @throws KeystoreServiceException if loading fails
+     */
+    KeyStore loadTruststore(String path, String keystoreType, String password)
+        throws KeystoreServiceException;
 }

Reply via email to