KNOX-2534. Allow alias to be used in pac4j topology block (#473)

diff --git a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
index bfea7ab..8abd2a3 100644
--- a/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
+++ b/gateway-provider-security-pac4j/src/main/java/org/apache/knox/gateway/pac4j/filter/Pac4jDispatcherFilter.java
@@ -23,8 +23,8 @@
 import org.apache.knox.gateway.pac4j.config.ClientConfigurationDecorator;
 import org.apache.knox.gateway.pac4j.config.Pac4jClientConfigurationDecorator;
 import org.apache.knox.gateway.pac4j.session.KnoxSessionStore;
-import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.GatewayServices;
+import org.apache.knox.gateway.services.ServiceType;
 import org.apache.knox.gateway.services.security.AliasService;
 import org.apache.knox.gateway.services.security.AliasServiceException;
 import org.apache.knox.gateway.services.security.CryptoService;
@@ -72,7 +72,7 @@
  * @since 0.8.0
  */
 public class Pac4jDispatcherFilter implements Filter {
-
+  private static final String ALIAS_PREFIX = "${ALIAS=";
   private static Pac4jMessages log = MessagesFactory.get(Pac4jMessages.class);
 
   private static final ClientConfigurationDecorator PAC4J_CLIENT_CONFIGURATION_DECORATOR = new Pac4jClientConfigurationDecorator();
@@ -175,7 +175,7 @@
       addDefaultConfig(clientNameParameter, properties);
       while (names.hasMoreElements()) {
         final String key = names.nextElement();
-        properties.put(key, filterConfig.getInitParameter(key));
+        properties.put(key, resolveAlias(clusterName, key, filterConfig.getInitParameter(key)));
       }
       final PropertiesConfigFactory propertiesConfigFactory = new PropertiesConfigFactory(pac4jCallbackUrl, properties);
       config = propertiesConfigFactory.build();
@@ -214,6 +214,18 @@
 
   }
 
+  private String resolveAlias(String clusterName, String key, String value) throws ServletException {
+    if (value.startsWith(ALIAS_PREFIX) && value.endsWith("}")) {
+      String alias = value.substring(ALIAS_PREFIX.length(), value.length() - 1);
+      try {
+        return new String(aliasService.getPasswordFromAliasForCluster(clusterName, alias));
+      } catch (AliasServiceException e) {
+        throw new ServletException("Unable to retrieve alias for config: " + key, e);
+      }
+    }
+    return value;
+  }
+
   private void addDefaultConfig(String clientNameParameter, Map<String, String> properties) {
     // add default saml params
     if (clientNameParameter.contains(SAML2Client.class.getSimpleName())) {
diff --git a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
index 6671554..e73d8fe 100644
--- a/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
+++ b/gateway-provider-security-pac4j/src/test/java/org/apache/knox/gateway/pac4j/Pac4jProviderTest.java
@@ -36,9 +36,11 @@
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletContext;
 import javax.servlet.http.Cookie;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 import java.util.stream.Collectors;
 
 import static org.junit.Assert.assertEquals;
@@ -367,4 +369,68 @@
         assertEquals(USERNAME, adapter.getTestIdentifier());
     }
 
+    @Test
+    public void testResolvesAlias() throws Exception {
+        final AliasService aliasService = EasyMock.createNiceMock(AliasService.class);
+        EasyMock.expect(aliasService.getPasswordFromAliasForCluster(CLUSTER_NAME, KnoxSessionStore.PAC4J_PASSWORD, true))
+                .andReturn(PAC4J_PASSWORD.toCharArray()).anyTimes();
+        EasyMock.expect(aliasService.getPasswordFromAliasForCluster(CLUSTER_NAME, KnoxSessionStore.PAC4J_PASSWORD))
+                .andReturn(PAC4J_PASSWORD.toCharArray()).anyTimes();
+        EasyMock.expect(aliasService.getPasswordFromAliasForCluster(CLUSTER_NAME, "my-secret-alias"))
+                .andReturn("my-oidc-secret".toCharArray()).atLeastOnce();
+        EasyMock.replay(aliasService);
+
+        GatewayServices services = EasyMock.createNiceMock(GatewayServices.class);
+        EasyMock.expect(services.getService(ServiceType.CRYPTO_SERVICE)).andReturn(new DefaultCryptoService());
+        EasyMock.expect(services.getService(ServiceType.ALIAS_SERVICE)).andReturn(aliasService);
+        EasyMock.replay(services);
+
+        ServletContext context = EasyMock.createNiceMock(ServletContext.class);
+        EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE)).andReturn(services);
+        EasyMock.expect(context.getAttribute(GatewayServices.GATEWAY_CLUSTER_ATTRIBUTE)).andReturn(CLUSTER_NAME);
+        EasyMock.replay(context);
+
+        new Pac4jDispatcherFilter().init(
+            new FilterConfigStub(context)
+                .addInitParam(Pac4jDispatcherFilter.PAC4J_CALLBACK_URL, PAC4J_CALLBACK_URL)
+                .addInitParam("clientName", "OidcClient")
+                .addInitParam("oidc.secret", "${ALIAS=my-secret-alias}")
+                .addInitParam("oidc.id", "test-id")
+        );
+        EasyMock.verify(aliasService);
+    }
+
+    private class FilterConfigStub implements FilterConfig {
+        private ServletContext context;
+        private Properties properties = new Properties();
+
+        FilterConfigStub(ServletContext context) {
+            this.context = context;
+        }
+
+        public FilterConfigStub addInitParam(String name, String value) {
+            properties.setProperty(name, value);
+            return this;
+        }
+
+        @Override
+        public String getFilterName() {
+            return null;
+        }
+
+        @Override
+        public ServletContext getServletContext() {
+            return context;
+        }
+
+        @Override
+        public String getInitParameter(String s) {
+            return properties.getProperty(s, null);
+        }
+
+        @Override
+        public Enumeration<String> getInitParameterNames() {
+            return (Enumeration<String>) properties.propertyNames();
+        }
+    }
 }