You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fineract.apache.org by al...@apache.org on 2022/02/20 23:08:54 UTC

[fineract] branch 1.6.0 updated: FINERACT-1490: SSL configuration based on application.properties

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

aleks pushed a commit to branch 1.6.0
in repository https://gitbox.apache.org/repos/asf/fineract.git


The following commit(s) were added to refs/heads/1.6.0 by this push:
     new 3e29d31  FINERACT-1490: SSL configuration based on application.properties
3e29d31 is described below

commit 3e29d31706951f01f0f46e366464ffbb4f03ded0
Author: Aleksandar Vidakovic <ch...@monkeysintown.com>
AuthorDate: Mon Jan 17 01:59:49 2022 +0100

    FINERACT-1490: SSL configuration based on application.properties
---
 README.md                                          |  13 +++
 .../org/apache/fineract/ServerApplication.java     |   3 -
 .../boot/EmbeddedTomcatWithSSLConfiguration.java   | 112 ---------------------
 .../core/config/OAuth2SecurityConfig.java          |  13 ++-
 .../infrastructure/core/config/SecurityConfig.java |  12 ++-
 .../src/main/resources/application.properties      |  18 ++++
 .../EmbeddedTomcatWithSSLConfigurationTest.java    |  56 -----------
 .../src/test/resources/application-test.properties |   8 ++
 integration-tests/build.gradle                     |   1 +
 9 files changed, 61 insertions(+), 175 deletions(-)

diff --git a/README.md b/README.md
index 767629f..eb8ca68 100644
--- a/README.md
+++ b/README.md
@@ -186,6 +186,19 @@ Please check `application.properties` to see which connection pool settings can
 
 NOTE: we'll keep backwards compatibility until one of the next releases to ensure that things are working as expected. Environment variables prefixed `fineract_tenants_*` can still be used to configure the database connection, but we strongly encourage using `FINERACT_HIKARI_*` with more options.
 
+SSL configuration
+=================
+
+By default SSL is enabled, but all SSL related properties are now tunable. SSL can be turned off by setting the environment variable `FINERACT_SERVER_SSL_ENABLED` to false. If you do that then please make sure to also change the server port to `8080` via the variable `FINERACT_SERVER_PORT`, just for the sake of keeping the conventions.
+You can choose now easily a different SSL keystore by setting `FINERACT_SERVER_SSL_KEY_STORE` with a path to a different (not embedded) keystore. The password can be set via `FINERACT_SERVER_SSL_KEY_STORE_PASSWORD`. See the `application.properties` file and the latest Spring Boot documentation (https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html) for more details.
+
+
+Tomcat configuration
+====================
+
+Please refer to the `application.properties` and the official Spring Boot documentation (https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html) on how to do performance tuning for Tomcat. Note: you can set now the acceptable form POST size (default is 2MB) via environment variable `FINERACT_SERVER_TOMCAT_MAX_HTTP_FORM_POST_SIZE`.
+
+
 Instructions to run on Kubernetes
 =================================
 
diff --git a/fineract-provider/src/main/java/org/apache/fineract/ServerApplication.java b/fineract-provider/src/main/java/org/apache/fineract/ServerApplication.java
index e206351..f567a6c 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/ServerApplication.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/ServerApplication.java
@@ -20,12 +20,10 @@ package org.apache.fineract;
 
 import java.io.IOException;
 import org.apache.fineract.infrastructure.core.boot.AbstractApplicationConfiguration;
-import org.apache.fineract.infrastructure.core.boot.EmbeddedTomcatWithSSLConfiguration;
 import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.annotation.Import;
 
 /**
  * Fineract main() application which launches Fineract in an embedded Tomcat HTTP (using Spring Boot).
@@ -42,7 +40,6 @@ import org.springframework.context.annotation.Import;
 
 public class ServerApplication extends SpringBootServletInitializer {
 
-    @Import({ EmbeddedTomcatWithSSLConfiguration.class })
     private static class Configuration extends AbstractApplicationConfiguration {}
 
     @Override
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/EmbeddedTomcatWithSSLConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/EmbeddedTomcatWithSSLConfiguration.java
deleted file mode 100644
index 8f5d26c..0000000
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/EmbeddedTomcatWithSSLConfiguration.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.infrastructure.core.boot;
-
-import java.io.File;
-import java.io.IOException;
-import java.net.URL;
-import org.apache.catalina.connector.Connector;
-import org.apache.commons.io.FileUtils;
-import org.apache.coyote.http11.Http11NioProtocol;
-import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
-import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-
-@Configuration
-public class EmbeddedTomcatWithSSLConfiguration {
-
-    // https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/howto.html#howto-enable-multiple-connectors-in-tomcat
-
-    @Bean
-    public ServletWebServerFactory servletContainer() {
-        TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();
-        tomcat.setContextPath(getContextPath());
-        tomcat.addAdditionalTomcatConnectors(createSslConnector());
-        return tomcat;
-    }
-
-    private String getContextPath() {
-        return "/fineract-provider";
-    }
-
-    protected Connector createSslConnector() {
-        Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
-        Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
-        try {
-            File keystore = getFile(getKeystore());
-            connector.setScheme("https");
-            connector.setSecure(true);
-            connector.setPort(getHTTPSPort());
-            protocol.setSSLEnabled(true);
-            protocol.setKeystoreFile(keystore.getAbsolutePath());
-            protocol.setKeystorePass(getKeystorePass());
-            return connector;
-        } catch (IOException ex) {
-            throw new IllegalStateException("can't access keystore: [" + "keystore" + "] or truststore: [" + "keystore" + "]", ex);
-        }
-    }
-
-    protected int getHTTPSPort() {
-        // TODO This shouldn't be hard-coded here, but configurable
-        return 8443;
-    }
-
-    protected String getKeystorePass() {
-        return "openmf";
-    }
-
-    protected Resource getKeystore() {
-        return new ClassPathResource("/keystore.jks");
-    }
-
-    public File getFile(Resource resource) throws IOException {
-        try {
-            return resource.getFile();
-        } catch (IOException e) {
-            // Uops.. OK, try again (below)
-        }
-
-        try {
-            URL url = resource.getURL();
-            /**
-             * // If this creates filenames that are too long on Win, // then could just use resource.getFilename(), //
-             * even though not unique, real risk prob. min.bon String tempDir = System.getProperty("java.io.tmpdir");
-             * tempDir = tempDir + "/" + getClass().getSimpleName() + "/"; String path = url.getPath(); String uniqName
-             * = path.replace("file:/", "").replace('!', '_'); String tempFullPath = tempDir + uniqName;
-             **/
-            // instead of File.createTempFile(prefix?, suffix?);
-            File targetFile = new File(resource.getFilename());
-            long len = resource.contentLength();
-            if (!targetFile.exists() || targetFile.length() != len) { // Only
-                                                                      // copy
-                                                                      // new
-                                                                      // files
-                FileUtils.copyURLToFile(url, targetFile);
-            }
-            return targetFile;
-        } catch (IOException e) {
-            // Uops.. erm, give up:
-            throw new IOException("Cannot obtain a File for Resource: " + resource.toString(), e);
-        }
-
-    }
-}
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
index 32202a6..6266d1e 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/OAuth2SecurityConfig.java
@@ -30,6 +30,7 @@ import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatfor
 import org.apache.fineract.infrastructure.security.vote.SelfServiceUserAccessVote;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -72,6 +73,9 @@ public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
     @Autowired
     private TenantAwareJpaPlatformUserDetailsService userDetailsService;
 
+    @Autowired
+    private ServerProperties serverProperties;
+
     private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
 
     @Override
@@ -97,8 +101,13 @@ public class OAuth2SecurityConfig extends WebSecurityConfigurerAdapter {
                 .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
                 .and() //
                 .addFilterAfter(tenantAwareTenantIdentifierFilter, SecurityContextPersistenceFilter.class) //
-                .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
-                .requiresChannel(channel -> channel.antMatchers("/api/**").requiresSecure());
+                .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class); //
+
+        if (serverProperties.getSsl().isEnabled()) {
+            http.requiresChannel(channel -> channel.antMatchers("/api/**").requiresSecure());
+        } else {
+            http.requiresChannel(channel -> channel.antMatchers("/api/**").requiresInsecure());
+        }
     }
 
     @Bean
diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
index 8fac767..ed9dce5 100644
--- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
+++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/SecurityConfig.java
@@ -24,6 +24,7 @@ import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticatio
 import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
 import org.springframework.boot.web.servlet.FilterRegistrationBean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -52,6 +53,9 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
     @Autowired
     private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
 
+    @Autowired
+    private ServerProperties serverProperties;
+
     @Override
     protected void configure(HttpSecurity http) throws Exception {
 
@@ -74,9 +78,13 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 .sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
                 .and() //
                 .addFilterAfter(tenantAwareBasicAuthenticationFilter(), SecurityContextPersistenceFilter.class) //
-                .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
-                .requiresChannel(channel -> channel.antMatchers("/api/**").requiresSecure());
+                .addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class); //
 
+        if (serverProperties.getSsl().isEnabled()) {
+            http.requiresChannel(channel -> channel.antMatchers("/api/**").requiresSecure());
+        } else {
+            http.requiresChannel(channel -> channel.antMatchers("/api/**").requiresInsecure());
+        }
     }
 
     @Bean
diff --git a/fineract-provider/src/main/resources/application.properties b/fineract-provider/src/main/resources/application.properties
index 92b6f4e..bbb251d 100644
--- a/fineract-provider/src/main/resources/application.properties
+++ b/fineract-provider/src/main/resources/application.properties
@@ -46,6 +46,24 @@ management.endpoints.web.exposure.include=health,info
 
 # FINERACT-914
 server.forward-headers-strategy=framework
+server.port=${FINERACT_SERVER_PORT:8443}
+server.servlet.context-path=${FINERACT_SERVER_SERVLET_CONTEXT_PATH:/fineract-provider}
+server.compression.enabled=${FINERACT_SERVER_COMPRESSION_ENABLED:true}
+
+server.ssl.enabled=${FINERACT_SERVER_SSL_ENABLED:true}
+server.ssl.protocol=TLS
+#server.ssl.ciphers=${FINERACT_SERVER_SSL_CIPHERS:TLS_RSA_WITH_AES_128_CBC_SHA256}
+#server.ssl.enabled-protocols=${FINERACT_SERVER_SSL_PROTOCOLS:TLSv1.2}
+server.ssl.key-store=${FINERACT_SERVER_SSL_KEY_STORE:classpath:keystore.jks}
+server.ssl.key-store-password=${FINERACT_SERVER_SSL_KEY_STORE_PASSWORD:openmf}
+
+server.tomcat.accept-count=${FINERACT_SERVER_TOMCAT_ACCEPT_COUNT:100}
+server.tomcat.accesslog.enabled=${FINERACT_SERVER_TOMCAT_ACCESSLOG_ENABLED:false}
+server.tomcat.max-connections=${FINERACT_SERVER_TOMCAT_MAX_CONNECTIONS:8192}
+server.tomcat.max-http-form-post-size=${FINERACT_SERVER_TOMCAT_MAX_HTTP_FORM_POST_SIZE:2MB}
+server.tomcat.max-keep-alive-requests=${FINERACT_SERVER_TOMCAT_MAX_KEEP_ALIVE_REQUESTS:100}
+server.tomcat.threads.max=${FINERACT_SERVER_TOMCAT_THREADS_MAX:200}
+server.tomcat.threads.min-spare=${FINERACT_SERVER_TOMCAT_THREADS_MIN_SPARE:10}
 
 # OAuth authorisation server endpoint
 spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:9000/auth/realms/fineract
diff --git a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/EmbeddedTomcatWithSSLConfigurationTest.java b/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/EmbeddedTomcatWithSSLConfigurationTest.java
deleted file mode 100644
index b16f7d3..0000000
--- a/fineract-provider/src/test/java/org/apache/fineract/infrastructure/core/boot/tests/EmbeddedTomcatWithSSLConfigurationTest.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.fineract.infrastructure.core.boot.tests;
-
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import java.io.File;
-import java.io.IOException;
-
-import org.apache.fineract.infrastructure.core.boot.EmbeddedTomcatWithSSLConfiguration;
-import org.junit.jupiter.api.Test;
-import org.springframework.core.io.ClassPathResource;
-import org.springframework.core.io.Resource;
-
-public class EmbeddedTomcatWithSSLConfigurationTest {
-
-    @Test
-    public void testGetFileWithFileResource() throws IOException {
-        // Test class probably isn't in a JAR
-        checkClassResource(getClass());
-    }
-
-    @Test
-    public void testGetFileWithClasspathResource() throws IOException {
-        // Spring Resource class probably is in a JAR
-        File f1 = checkClassResource(Resource.class);
-        f1.delete();
-        checkClassResource(Resource.class);
-    }
-
-    protected File checkClassResource(Class<?> clazz) throws IOException {
-        String testClasspathResourcePath = clazz.getCanonicalName().replace('.', '/') + ".class";
-        Resource r = new ClassPathResource(testClasspathResourcePath);
-        File f = new EmbeddedTomcatWithSSLConfiguration().getFile(r);
-        assertTrue(f.exists());
-        f = new EmbeddedTomcatWithSSLConfiguration().getFile(r);
-        assertTrue(f.exists());
-        return f;
-    }
-}
diff --git a/fineract-provider/src/test/resources/application-test.properties b/fineract-provider/src/test/resources/application-test.properties
index 6a6f765..b778947 100644
--- a/fineract-provider/src/test/resources/application-test.properties
+++ b/fineract-provider/src/test/resources/application-test.properties
@@ -46,6 +46,14 @@ management.endpoints.web.exposure.include=health,info
 
 # FINERACT-914
 server.forward-headers-strategy=framework
+server.port=8443
+server.servlet.context-path=/fineract-provider
+server.compression.enabled=true
+
+server.ssl.enabled=true
+server.ssl.protocol=TLS
+server.ssl.key-store=keystore.jks
+server.ssl.key-store-password=openmf
 
 spring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver
 spring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants
diff --git a/integration-tests/build.gradle b/integration-tests/build.gradle
index 3590869..4d4cfb8 100644
--- a/integration-tests/build.gradle
+++ b/integration-tests/build.gradle
@@ -38,6 +38,7 @@ cargo {
     }
 
     local {
+        logLevel = 'medium'
         installer {
             installConfiguration = configurations.tomcat
             downloadDir = file("$buildDir/download")