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

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

commit a7d5f834d5f6af5a05cbad540dee49fdb8ddb8bf
Author: Arnold Galovics <[email protected]>
AuthorDate: Thu Jun 1 14:27:06 2023 +0200

    FINERACT-1724: EclipseLink upgrade fixes + Spring Security chain fixes
---
 build.gradle                                       |   2 +-
 .../groovy/org.apache.fineract.dependencies.gradle |   5 +-
 .../src/main/resources/META-INF/spring.factories   |   2 -
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   1 +
 .../src/main/resources/META-INF/spring.factories   |   2 -
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   1 +
 .../src/main/resources/META-INF/spring.factories   |   2 -
 ...rk.boot.autoconfigure.AutoConfiguration.imports |   1 +
 .../infrastructure/core/boot/FineractProfiles.java |   1 +
 .../core/config/FineractProperties.java            |  36 +++++
 .../core/config/OAuth2SecurityConfig.java          |  67 +++++----
 .../infrastructure/core/config/SecurityConfig.java | 155 +++++++++++++++------
 .../core/config/TomcatConnectorCustomizer.java     |  36 -----
 .../diagnostics/jpa/DiagnosticsEntityManager.java  |   3 +-
 .../security/SecurityFilterChainDiagnostics.java   |  81 +++++++++++
 .../core/filters/CorrelationHeaderFilter.java      |   4 +-
 .../core/filters/IdempotencyStoreFilter.java       |   8 +-
 .../core/filters/RequestResponseFilter.java        |   4 +-
 .../core/filters/ResponseCorsFilter.java           |  33 ++---
 .../infrastructure/core/jersey/JerseyConfig.java   |   2 +-
 .../filter/FineractInstanceModeApiFilter.java      |   8 +-
 .../jobs/filter/LoanCOBApiFilter.java              |  10 +-
 .../InsecureTwoFactorAuthenticationFilter.java     |  12 +-
 .../TenantAwareBasicAuthenticationFilter.java      | 125 ++++++++---------
 .../filter/TwoFactorAuthenticationFilter.java      |  20 +--
 .../src/main/resources/META-INF/orm.xml            |  16 +--
 integration-tests/dependencies.gradle              |   2 +
 .../bulkimport/importhandler/loan/Loan.xls         | Bin 0 -> 2328576 bytes
 .../bulkimport/importhandler/office/Office.xls     | Bin 0 -> 359936 bytes
 .../bulkimport/importhandler/savings/Savings.xls   | Bin 0 -> 1843712 bytes
 30 files changed, 393 insertions(+), 246 deletions(-)

diff --git a/build.gradle b/build.gradle
index 3705b7e25..257598e7f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -55,7 +55,7 @@ buildscript {
 
     dependencies {
         classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0'
-        classpath 'org.eclipse.persistence:eclipselink:4.0.1'
+        classpath 'org.eclipse.persistence:eclipselink:4.0.0'
         classpath 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
         classpath 
'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.3.0'
         classpath 'org.apache.commons:commons-lang3:3.12.0'
diff --git a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle 
b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle
index 9070653b9..f6caf1c4b 100644
--- a/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle
+++ b/buildSrc/src/main/groovy/org.apache.fineract.dependencies.gradle
@@ -50,7 +50,7 @@ dependencyManagement {
         dependency 'org.codehaus.janino:janino:3.1.9'
 
 
-        dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:4.0.1'
+        dependency 'org.eclipse.persistence:org.eclipse.persistence.jpa:4.0.0'
         dependency 'com.google.guava:guava:31.1-jre'
         dependency 'com.google.code.gson:gson:2.10.1'
         dependency 'com.google.truth:truth:1.1.3'
@@ -64,6 +64,7 @@ dependencyManagement {
         dependency 'com.github.librepdf:openpdf:1.3.30'
         dependency ('org.mnode.ical4j:ical4j:3.2.11') {
             exclude 'com.sun.mail:javax.mail'
+            exclude 'org.codehaus.groovy:groovy'
         }
         dependency 'org.apache.commons:commons-csv:1.10.0'
         dependency 'org.quartz-scheduler:quartz:2.3.2'
@@ -233,6 +234,8 @@ dependencyManagement {
             entry 'json-path'
             entry 'xml-path'
         }
+        dependency 'org.apache.groovy:groovy-xml:4.0.6'
+        dependency 'org.apache.groovy:groovy-json:4.0.6'
 
         dependency 'org.mapstruct:mapstruct:1.5.4.Final'
         dependency 'org.mapstruct:mapstruct-processor:1.5.4.Final'
diff --git 
a/custom/acme/event/starter/src/main/resources/META-INF/spring.factories 
b/custom/acme/event/starter/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index 28d54193a..000000000
--- a/custom/acme/event/starter/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1,2 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-com.acme.fineract.event.starter.AcmeEventAutoConfiguration
\ No newline at end of file
diff --git 
a/custom/acme/event/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/custom/acme/event/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..27bbb4632
--- /dev/null
+++ 
b/custom/acme/event/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.acme.fineract.event.starter.AcmeEventAutoConfiguration
\ No newline at end of file
diff --git 
a/custom/acme/loan/starter/src/main/resources/META-INF/spring.factories 
b/custom/acme/loan/starter/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index a3c5b7e58..000000000
--- a/custom/acme/loan/starter/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1,2 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-com.acme.fineract.loan.starter.AcmeLoanAutoConfiguration
\ No newline at end of file
diff --git 
a/custom/acme/loan/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/custom/acme/loan/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..a900f8060
--- /dev/null
+++ 
b/custom/acme/loan/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.acme.fineract.loan.starter.AcmeLoanAutoConfiguration
\ No newline at end of file
diff --git 
a/custom/acme/note/starter/src/main/resources/META-INF/spring.factories 
b/custom/acme/note/starter/src/main/resources/META-INF/spring.factories
deleted file mode 100644
index d3f0e811b..000000000
--- a/custom/acme/note/starter/src/main/resources/META-INF/spring.factories
+++ /dev/null
@@ -1,2 +0,0 @@
-org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
-com.acme.fineract.portfolio.note.starter.AcmeNoteAutoConfiguration
\ No newline at end of file
diff --git 
a/custom/acme/note/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
 
b/custom/acme/note/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 000000000..c20803e4a
--- /dev/null
+++ 
b/custom/acme/note/starter/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1 @@
+com.acme.fineract.portfolio.note.starter.AcmeNoteAutoConfiguration
\ No newline at end of file
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/FineractProfiles.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/FineractProfiles.java
index e07173efc..6d0757021 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/FineractProfiles.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/boot/FineractProfiles.java
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.core.boot;
 public final class FineractProfiles {
 
     public static final String LIQUIBASE_ONLY = "liquibase-only";
+    public static final String DIAGNOSTICS = "diagnostics";
 
     private FineractProfiles() {}
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
index 3afa01687..3ef3c4acb 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/FineractProperties.java
@@ -57,6 +57,7 @@ public class FineractProperties {
 
     private FineractQueryProperties query;
     private FineractApiProperties api;
+    private FineractSecurityProperties security;
 
     private FineractNotificationProperties notification;
 
@@ -352,6 +353,41 @@ public class FineractProperties {
         private boolean errorNotFoundFail;
     }
 
+    @Getter
+    @Setter
+    public static class FineractSecurityProperties {
+
+        private FineractSecurityBasicAuth basicauth;
+        private FineractSecurityTwoFactorAuth twoFactor;
+        private FineractSecurityOAuth oauth;
+
+        public void set2fa(FineractSecurityTwoFactorAuth twoFactor) {
+            this.twoFactor = twoFactor;
+        }
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSecurityBasicAuth {
+
+        private boolean enabled;
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSecurityTwoFactorAuth {
+
+        private boolean enabled;
+    }
+
+    @Getter
+    @Setter
+    public static class FineractSecurityOAuth {
+
+        private boolean enabled;
+    }
+
+
     @Getter
     @Setter
     public static class FineractTransactionProcessorItemProperties {
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 9a6c59213..37caef0a9 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
@@ -25,15 +25,21 @@ import static 
org.springframework.security.authorization.AuthorityAuthorizationM
 import static 
org.springframework.security.authorization.AuthorizationManagers.allOf;
 
 import java.util.Collection;
+import 
org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
+import 
org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
+import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
 import 
org.apache.fineract.infrastructure.core.exceptionmapper.OAuth2ExceptionEntryPoint;
+import 
org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
 import 
org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
+import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
 import 
org.apache.fineract.infrastructure.security.filter.TenantAwareTenantIdentifierFilter;
 import 
org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
+import 
org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
 import 
org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
+import org.apache.fineract.infrastructure.security.service.TwoFactorService;
 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;
 import org.springframework.core.convert.converter.Converter;
@@ -55,25 +61,36 @@ import org.springframework.security.web.SecurityFilterChain;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
 import org.springframework.security.web.context.SecurityContextHolderFilter;
 
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ConditionalOnProperty("fineract.security.oauth.enabled")
 @EnableMethodSecurity
 public class OAuth2SecurityConfig {
 
     @Autowired
-    private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
+    private TenantAwareJpaPlatformUserDetailsService userDetailsService;
 
     @Autowired
-    private TenantAwareTenantIdentifierFilter 
tenantAwareTenantIdentifierFilter;
+    private ServerProperties serverProperties;
 
     @Autowired
-    private TenantAwareJpaPlatformUserDetailsService userDetailsService;
+    private TwoFactorService twoFactorService;
 
     @Autowired
-    private ServerProperties serverProperties;
+    private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
 
-    private static final JwtGrantedAuthoritiesConverter 
jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
+    @Autowired
+    private ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
 
+    @Autowired
+    private ConfigurationDomainService configurationDomainService;
+
+    @Autowired
+    private CacheWritePlatformService cacheWritePlatformService;
+
+    @Autowired
+    private BusinessDateReadPlatformService businessDateReadPlatformService;
+
+    private static final JwtGrantedAuthoritiesConverter 
jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
 
     @Bean
     public SecurityFilterChain authorizationFilterChain(HttpSecurity http) 
throws Exception {
@@ -90,26 +107,40 @@ public class OAuth2SecurityConfig {
                             
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
                             
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), 
hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
                 });
+
+        if (serverProperties.getSsl().isEnabled()) {
+            http.requiresChannel(channel -> 
channel.requestMatchers("/api/**").requiresSecure());
+        }
+
         return http.build();
     }
 
     @Bean
-    public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception 
{
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception 
{
         http //
                 .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a 
service that is used by non-browser clients
                 .exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new 
OAuth2ExceptionEntryPoint()))
                 .oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> 
jwt.jwtAuthenticationConverter(authenticationConverter()))
                         .authenticationEntryPoint(new 
OAuth2ExceptionEntryPoint())) //
                 .sessionManagement((smc) -> 
smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
-                .addFilterAfter(tenantAwareTenantIdentifierFilter, 
SecurityContextHolderFilter.class) //
-                .addFilterAfter(twoFactorAuthenticationFilter, 
BasicAuthenticationFilter.class); //
+                .addFilterAfter(tenantAwareTenantIdentifierFilter(), 
SecurityContextHolderFilter.class) //
+                .addFilterAfter(twoFactorAuthenticationFilter(), 
BasicAuthenticationFilter.class); //
 
         if (serverProperties.getSsl().isEnabled()) {
             http.requiresChannel(channel -> 
channel.requestMatchers("/api/**").requiresSecure());
         }
+
         return http.build();
     }
 
+    public TenantAwareTenantIdentifierFilter 
tenantAwareTenantIdentifierFilter() {
+        return new 
TenantAwareTenantIdentifierFilter(basicAuthTenantDetailsService, 
toApiJsonSerializer, configurationDomainService, cacheWritePlatformService, 
businessDateReadPlatformService);
+    }
+
+    public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
+        return new TwoFactorAuthenticationFilter(twoFactorService);
+    }
+
     @Bean
     public PasswordEncoder passwordEncoder() {
         return PasswordEncoderFactories.createDelegatingPasswordEncoder();
@@ -127,20 +158,4 @@ public class OAuth2SecurityConfig {
             }
         };
     }
-
-    @Bean
-    public FilterRegistrationBean<TenantAwareTenantIdentifierFilter> 
tenantAwareTenantIdentifierFilterRegistration() throws Exception {
-        FilterRegistrationBean<TenantAwareTenantIdentifierFilter> registration 
= new FilterRegistrationBean<TenantAwareTenantIdentifierFilter>(
-                tenantAwareTenantIdentifierFilter);
-        registration.setEnabled(false);
-        return registration;
-    }
-
-    @Bean
-    public FilterRegistrationBean<TwoFactorAuthenticationFilter> 
twoFactorAuthenticationFilterRegistration() {
-        FilterRegistrationBean<TwoFactorAuthenticationFilter> registration = 
new FilterRegistrationBean<TwoFactorAuthenticationFilter>(
-                twoFactorAuthenticationFilter);
-        registration.setEnabled(false);
-        return registration;
-    }
 }
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 a1899b5c2..7fb093c6b 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
@@ -23,17 +23,38 @@ import static 
org.springframework.security.authorization.AuthenticatedAuthorizat
 import static 
org.springframework.security.authorization.AuthorityAuthorizationManager.hasAuthority;
 import static 
org.springframework.security.authorization.AuthorizationManagers.allOf;
 
+import org.apache.fineract.cob.service.InlineLoanCOBExecutorServiceImpl;
+import org.apache.fineract.cob.service.LoanAccountLockService;
+import org.apache.fineract.commands.domain.CommandSourceRepository;
+import org.apache.fineract.commands.service.CommandSourceService;
+import 
org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
+import 
org.apache.fineract.infrastructure.cache.service.CacheWritePlatformService;
+import 
org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
+import 
org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
+import org.apache.fineract.infrastructure.core.filters.CorrelationHeaderFilter;
 import org.apache.fineract.infrastructure.core.filters.IdempotencyStoreFilter;
+import org.apache.fineract.infrastructure.core.filters.RequestResponseFilter;
+import org.apache.fineract.infrastructure.core.filters.ResponseCorsFilter;
+import 
org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
+import org.apache.fineract.infrastructure.core.service.MDCWrapper;
 import 
org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter;
 import org.apache.fineract.infrastructure.jobs.filter.LoanCOBApiFilter;
+import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
 import 
org.apache.fineract.infrastructure.security.filter.InsecureTwoFactorAuthenticationFilter;
 import 
org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
 import 
org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
+import 
org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
+import 
org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
 import 
org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
+import org.apache.fineract.infrastructure.security.service.TwoFactorService;
+import org.apache.fineract.notification.service.UserNotificationService;
+import 
org.apache.fineract.portfolio.loanaccount.domain.GLIMAccountInfoRepository;
+import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
+import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequestRepository;
 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.ApplicationContext;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpMethod;
@@ -48,24 +69,18 @@ import 
org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.access.ExceptionTranslationFilter;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
-import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
-import org.springframework.security.web.context.SecurityContextHolderFilter;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.transaction.PlatformTransactionManager;
 
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ConditionalOnProperty("fineract.security.basicauth.enabled")
 @EnableMethodSecurity
 public class SecurityConfig {
-
-    @Autowired
-    private TenantAwareJpaPlatformUserDetailsService userDetailsService;
-
     @Autowired
-    private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
+    private ApplicationContext applicationContext;
 
     @Autowired
-    private FineractInstanceModeApiFilter fineractInstanceModeApiFilter;
-    @Autowired
-    private LoanCOBApiFilter loanCOBApiFilter;
+    private TenantAwareJpaPlatformUserDetailsService userDetailsService;
 
     @Autowired
     private FineractProperties fineractProperties;
@@ -74,8 +89,40 @@ public class SecurityConfig {
     private ServerProperties serverProperties;
 
     @Autowired
-    private IdempotencyStoreFilter idempotencyStoreFilter;
+    private ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
+    @Autowired
+    private ConfigurationDomainService configurationDomainService;
+    @Autowired
+    private CacheWritePlatformService cacheWritePlatformService;
+    @Autowired
+    private UserNotificationService userNotificationService;
+    @Autowired
+    private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
+    @Autowired
+    private BusinessDateReadPlatformService businessDateReadPlatformService;
+    @Autowired
+    private MDCWrapper mdcWrapper;
+    @Autowired
+    private CommandSourceRepository commandSourceRepository;
+    @Autowired
+    private CommandSourceService commandSourceService;
+    @Autowired
+    private FineractRequestContextHolder fineractRequestContextHolder;
 
+    @Autowired
+    private GLIMAccountInfoRepository glimAccountInfoRepository;
+    @Autowired
+    private LoanAccountLockService loanAccountLockService;
+    @Autowired
+    private PlatformSecurityContext context;
+    @Autowired
+    private InlineLoanCOBExecutorServiceImpl inlineLoanCOBExecutorService;
+    @Autowired
+    private LoanRepository loanRepository;
+    @Autowired
+    private LoanRescheduleRequestRepository loanRescheduleRequestRepository;
+    @Autowired
+    private PlatformTransactionManager transactionManager;
 
     @Bean
     public SecurityFilterChain authorizationFilterChain(HttpSecurity http) 
throws Exception {
@@ -93,7 +140,11 @@ public class SecurityConfig {
                             
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
                             
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), 
hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
                 }) //
-                .httpBasic((httpBasic) -> 
httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())); //
+                .httpBasic((httpBasic) -> 
httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint()));
+
+        if (serverProperties.getSsl().isEnabled()) {
+            http.requiresChannel(channel -> 
channel.requestMatchers("/api/**").requiresSecure());
+        }
         return http.build();
     }
 
@@ -101,22 +152,65 @@ public class SecurityConfig {
     public SecurityFilterChain filterChain(HttpSecurity http) throws Exception 
{
         http //
                 .csrf((csrf) -> csrf.disable()) // NOSONAR only creating a 
service that is used by non-browser clients
+                .securityContext((securityContext) -> 
securityContext.requireExplicitSave(false))
                 .sessionManagement((smc) -> 
smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
-                .addFilterAfter(fineractInstanceModeApiFilter, 
SecurityContextHolderFilter.class) //
+                .addFilterAfter(requestResponseFilter(), 
ExceptionTranslationFilter.class)
+                .addFilterAfter(correlationHeaderFilter(), 
RequestResponseFilter.class)
+                .addFilterAfter(responseCorsFilter(), 
CorrelationHeaderFilter.class) //
+                .addFilterAfter(fineractInstanceModeApiFilter(), 
ResponseCorsFilter.class) //
                 .addFilterAfter(tenantAwareBasicAuthenticationFilter(), 
FineractInstanceModeApiFilter.class) //
-                .addFilterAfter(twoFactorAuthenticationFilter, 
BasicAuthenticationFilter.class) //
-                .addFilterAfter(loanCOBApiFilter, 
InsecureTwoFactorAuthenticationFilter.class) //
-                .addFilterBefore(idempotencyStoreFilter, 
ExceptionTranslationFilter.class); //
+                .addFilterAfter(loanCOBApiFilter(), 
TenantAwareBasicAuthenticationFilter.class) //
+                .addFilterAfter(idempotencyStoreFilter(), 
LoanCOBApiFilter.class); //
 
-        if (serverProperties.getSsl().isEnabled()) {
-            http.requiresChannel(channel -> 
channel.requestMatchers("/api/**").requiresSecure());
+        if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) {
+            http.addFilterAfter(twoFactorAuthenticationFilter(), 
FineractInstanceModeApiFilter.class);
+        } else {
+            http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), 
FineractInstanceModeApiFilter.class);
         }
+
         return http.build();
     }
 
-    @Bean
+    public RequestResponseFilter requestResponseFilter() {
+        return new RequestResponseFilter();
+    }
+
+    public LoanCOBApiFilter loanCOBApiFilter() {
+        return new LoanCOBApiFilter(glimAccountInfoRepository, 
loanAccountLockService, context, inlineLoanCOBExecutorService, loanRepository, 
fineractProperties, loanRescheduleRequestRepository, transactionManager);
+    }
+
+    public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
+        TwoFactorService twoFactorService = 
applicationContext.getBean(TwoFactorService.class);
+        return new TwoFactorAuthenticationFilter(twoFactorService);
+    }
+
+    public InsecureTwoFactorAuthenticationFilter 
insecureTwoFactorAuthenticationFilter() {
+        return new InsecureTwoFactorAuthenticationFilter();
+    }
+
+    public FineractInstanceModeApiFilter fineractInstanceModeApiFilter() {
+        return new FineractInstanceModeApiFilter(fineractProperties);
+    }
+
+    public IdempotencyStoreFilter idempotencyStoreFilter() {
+        return new IdempotencyStoreFilter(commandSourceRepository, 
commandSourceService, fineractProperties, fineractRequestContextHolder);
+    }
+
+    public CorrelationHeaderFilter correlationHeaderFilter() {
+        return new CorrelationHeaderFilter(fineractProperties, mdcWrapper);
+    }
+
+    public ResponseCorsFilter responseCorsFilter() {
+        return new ResponseCorsFilter();
+    }
+
     public TenantAwareBasicAuthenticationFilter 
tenantAwareBasicAuthenticationFilter() throws Exception {
-        return new 
TenantAwareBasicAuthenticationFilter(authenticationManagerBean(), 
basicAuthenticationEntryPoint());
+        TenantAwareBasicAuthenticationFilter filter = new 
TenantAwareBasicAuthenticationFilter(authenticationManagerBean(), 
basicAuthenticationEntryPoint(),
+                toApiJsonSerializer, configurationDomainService, 
cacheWritePlatformService,
+                userNotificationService, basicAuthTenantDetailsService,
+                businessDateReadPlatformService);
+        filter.setRequestMatcher(AntPathRequestMatcher.antMatcher("/api/**"));
+        return filter;
     }
 
     @Bean
@@ -145,21 +239,4 @@ public class SecurityConfig {
         providerManager.setEraseCredentialsAfterAuthentication(false);
         return providerManager;
     }
-
-    @Bean
-    public FilterRegistrationBean<TenantAwareBasicAuthenticationFilter> 
tenantAwareBasicAuthenticationFilterRegistration()
-            throws Exception {
-        FilterRegistrationBean<TenantAwareBasicAuthenticationFilter> 
registration = new FilterRegistrationBean<TenantAwareBasicAuthenticationFilter>(
-                tenantAwareBasicAuthenticationFilter());
-        registration.setEnabled(false);
-        return registration;
-    }
-
-    @Bean
-    public FilterRegistrationBean<TwoFactorAuthenticationFilter> 
twoFactorAuthenticationFilterRegistration() {
-        FilterRegistrationBean<TwoFactorAuthenticationFilter> registration = 
new FilterRegistrationBean<TwoFactorAuthenticationFilter>(
-                twoFactorAuthenticationFilter);
-        registration.setEnabled(false);
-        return registration;
-    }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/TomcatConnectorCustomizer.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/TomcatConnectorCustomizer.java
deleted file mode 100644
index ef7576b48..000000000
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/config/TomcatConnectorCustomizer.java
+++ /dev/null
@@ -1,36 +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.config;
-
-import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
-import 
org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
-import org.springframework.boot.web.server.WebServerFactoryCustomizer;
-import 
org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
-import org.springframework.stereotype.Component;
-
-@Component
-@ConditionalOnClass(name = "org.apache.coyote.http11.Http11Nio2Protocol")
-public class TomcatConnectorCustomizer implements 
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
-
-    @Override
-    public void customize(ConfigurableServletWebServerFactory factory) {
-        ((TomcatServletWebServerFactory) 
factory).setProtocol("org.apache.coyote.http11.Http11Nio2Protocol");
-    }
-}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/jpa/DiagnosticsEntityManager.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/jpa/DiagnosticsEntityManager.java
index bc864a2ba..8975730f2 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/jpa/DiagnosticsEntityManager.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/jpa/DiagnosticsEntityManager.java
@@ -20,6 +20,7 @@ package 
org.apache.fineract.infrastructure.core.diagnostics.jpa;
 
 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
 import jakarta.persistence.EntityManagerFactory;
+import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
 import org.eclipse.persistence.internal.jpa.EntityManagerImpl;
 import org.eclipse.persistence.sessions.changesets.UnitOfWorkChangeSet;
 import org.springframework.beans.BeansException;
@@ -38,7 +39,7 @@ import org.springframework.stereotype.Component;
  * <br>
  * To enable this, run Fineract with the <b>diagnostics</b> profile.
  */
-@Profile("diagnostics")
+@Profile(FineractProfiles.DIAGNOSTICS)
 @Component
 public class DiagnosticsEntityManager implements ApplicationContextAware {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/security/SecurityFilterChainDiagnostics.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/security/SecurityFilterChainDiagnostics.java
new file mode 100644
index 000000000..3c5f90043
--- /dev/null
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/diagnostics/security/SecurityFilterChainDiagnostics.java
@@ -0,0 +1,81 @@
+/**
+ * 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.diagnostics.security;
+
+import static java.lang.System.lineSeparator;
+
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.annotation.Profile;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.stereotype.Component;
+
+@Component
+@Profile(FineractProfiles.DIAGNOSTICS)
+@Slf4j
+@RequiredArgsConstructor
+public class SecurityFilterChainDiagnostics implements InitializingBean {
+    private final List<SecurityFilterChain> filterChains;
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        filterChains.forEach(this::printFilterChain);
+    }
+
+    private void printFilterChain(SecurityFilterChain filterChain) {
+        if (filterChain instanceof DefaultSecurityFilterChain) {
+            printDefaultFilterChain((DefaultSecurityFilterChain) filterChain);
+        } else {
+            printUnknownFilterChain(filterChain);
+        }
+    }
+
+    private void printDefaultFilterChain(DefaultSecurityFilterChain 
filterChain) {
+
+        log.info(
+                """
+                
+                Filter chain matcher: %s
+                Filters in order:
+                %s
+                """.formatted(filterChain.getRequestMatcher(), 
getFormattedFilters(filterChain)));
+    }
+
+    private String getFormattedFilters(DefaultSecurityFilterChain filterChain) 
{
+        StringBuilder result = new StringBuilder();
+        filterChain.getFilters().forEach(f -> {
+            result.append("- ");
+            result.append(f.getClass().getName());
+            result.append(lineSeparator());
+        });
+        return result.toString();
+    }
+
+    private void printUnknownFilterChain(SecurityFilterChain filterChain) {
+        log.info(
+                """
+                Filter chain:
+                %s
+                """.formatted(filterChain));
+    }
+}
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
index 459464830..5797a8cf9 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/CorrelationHeaderFilter.java
@@ -19,23 +19,21 @@
 
 package org.apache.fineract.infrastructure.core.filters;
 
-import java.io.IOException;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 import org.apache.fineract.infrastructure.core.service.MDCWrapper;
 import 
org.apache.fineract.infrastructure.security.utils.LogParameterEscapeUtil;
-import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
 @RequiredArgsConstructor
 @Slf4j
-@Component
 public class CorrelationHeaderFilter extends OncePerRequestFilter {
 
     public static final String CORRELATION_ID_KEY = "correlationId";
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreFilter.java
index 0bfdf4f9e..6270b8e20 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/IdempotencyStoreFilter.java
@@ -18,14 +18,14 @@
  */
 package org.apache.fineract.infrastructure.core.filters;
 
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Optional;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.ws.rs.core.UriInfo;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Optional;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.mutable.Mutable;
@@ -39,13 +39,11 @@ import 
org.apache.fineract.commands.service.SynchronousCommandProcessingService;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 import 
org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
 import org.jetbrains.annotations.NotNull;
-import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 import org.springframework.web.util.ContentCachingResponseWrapper;
 
 @RequiredArgsConstructor
 @Slf4j
-@Component
 public class IdempotencyStoreFilter extends OncePerRequestFilter implements 
BatchFilter {
 
     private final CommandSourceRepository commandSourceRepository;
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/RequestResponseFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/RequestResponseFilter.java
index e900ca5f6..659efa861 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/RequestResponseFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/RequestResponseFilter.java
@@ -19,19 +19,17 @@
 
 package org.apache.fineract.infrastructure.core.filters;
 
-import java.io.IOException;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
 @RequiredArgsConstructor
 @Slf4j
-@Component
 public class RequestResponseFilter extends OncePerRequestFilter {
 
     @Override
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java
index 870464c4d..73c3dd580 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/filters/ResponseCorsFilter.java
@@ -18,36 +18,31 @@
  */
 package org.apache.fineract.infrastructure.core.filters;
 
-import jakarta.ws.rs.container.ContainerRequestContext;
-import jakarta.ws.rs.container.ContainerResponseContext;
-import jakarta.ws.rs.container.ContainerResponseFilter;
-import jakarta.ws.rs.ext.Provider;
-import org.springframework.context.annotation.Scope;
-import org.springframework.stereotype.Component;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
 import org.springframework.util.StringUtils;
+import org.springframework.web.filter.OncePerRequestFilter;
 
 /**
  * Filter that returns a response with headers that allows for Cross-Origin 
Requests (CORs) to be performed against the
  * platform API.
  */
 
-@Provider
-@Component
-@Scope("singleton")
-public class ResponseCorsFilter implements ContainerResponseFilter {
+public class ResponseCorsFilter extends OncePerRequestFilter {
 
     @Override
-    public void filter(final ContainerRequestContext request, final 
ContainerResponseContext response) {
+    protected void doFilterInternal(HttpServletRequest request, 
HttpServletResponse response, FilterChain filterChain) throws ServletException, 
IOException {
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, 
DELETE, OPTIONS");
 
-        response.getHeaders().add("Access-Control-Allow-Origin", "*");
-        // .header("Access-Control-Expose-Headers",
-        // "Fineract-Platform-TenantId")
-        response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, 
PUT, DELETE, OPTIONS");
+        final String reqHead = 
request.getHeader("Access-Control-Request-Headers");
 
-        final String reqHead = 
request.getHeaders().getFirst("Access-Control-Request-Headers");
-
-        if (null != reqHead && StringUtils.hasText(reqHead)) {
-            response.getHeaders().add("Access-Control-Allow-Headers", reqHead);
+        if (StringUtils.hasText(reqHead)) {
+            response.addHeader("Access-Control-Allow-Headers", reqHead);
         }
+        filterChain.doFilter(request, response);
     }
 }
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyConfig.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyConfig.java
index aaa1343ce..c5a18f0c0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyConfig.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/jersey/JerseyConfig.java
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.annotation.Configuration;
 
-@Configuration
+@Configuration(proxyBeanMethods = false)
 @ApplicationPath("/api")
 public class JerseyConfig extends ResourceConfig {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
index d940e4430..21db95724 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/instancemode/filter/FineractInstanceModeApiFilter.java
@@ -21,23 +21,21 @@ package 
org.apache.fineract.infrastructure.instancemode.filter;
 import static org.apache.commons.lang3.StringUtils.isBlank;
 import static 
org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter.ExceptionListItem.item;
 
-import java.io.IOException;
-import java.util.List;
-import java.util.function.Function;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import jakarta.ws.rs.HttpMethod;
+import java.io.IOException;
+import java.util.List;
+import java.util.function.Function;
 import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.fineract.infrastructure.core.config.FineractProperties;
 import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
 import org.apache.http.HttpStatus;
-import org.springframework.stereotype.Component;
 import org.springframework.web.filter.OncePerRequestFilter;
 
-@Component
 @RequiredArgsConstructor
 public class FineractInstanceModeApiFilter extends OncePerRequestFilter {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
index 356121259..19d51caa0 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/jobs/filter/LoanCOBApiFilter.java
@@ -22,6 +22,10 @@ import static 
org.apache.fineract.batch.command.CommandStrategyUtils.isRelativeU
 
 import com.google.common.collect.Lists;
 import io.github.resilience4j.core.functions.Either;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import java.io.IOException;
 import java.math.BigDecimal;
 import java.util.ArrayList;
@@ -29,10 +33,6 @@ import java.util.Collections;
 import java.util.List;
 import java.util.function.Predicate;
 import java.util.regex.Pattern;
-import jakarta.servlet.FilterChain;
-import jakarta.servlet.ServletException;
-import jakarta.servlet.http.HttpServletRequest;
-import jakarta.servlet.http.HttpServletResponse;
 import lombok.RequiredArgsConstructor;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -57,13 +57,11 @@ import 
org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanResch
 import 
org.apache.fineract.useradministration.exception.UnAuthenticatedUserException;
 import org.apache.http.HttpStatus;
 import org.springframework.http.HttpMethod;
-import org.springframework.stereotype.Component;
 import org.springframework.transaction.PlatformTransactionManager;
 import org.springframework.transaction.TransactionDefinition;
 import org.springframework.transaction.support.TransactionTemplate;
 import org.springframework.web.filter.OncePerRequestFilter;
 
-@Component
 @RequiredArgsConstructor
 public class LoanCOBApiFilter extends OncePerRequestFilter implements 
BatchRequestPreprocessor {
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java
index 7a1ea837c..85ef766fd 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/InsecureTwoFactorAuthenticationFilter.java
@@ -18,16 +18,15 @@
  */
 package org.apache.fineract.infrastructure.security.filter;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.ServletRequest;
 import jakarta.servlet.ServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import 
org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -35,15 +34,12 @@ import 
org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Service;
 
 /**
  * A dummy {@link TwoFactorAuthenticationFilter} filter used when 'twofactor' 
environment profile is not active.
  *
  * This filter adds 'TWOFACTOR_AUTHENTICATED' authority to every authenticated 
platform user.
  */
-@Service
-@ConditionalOnProperty(name = "fineract.security.2fa.enabled", havingValue = 
"false")
 public class InsecureTwoFactorAuthenticationFilter extends 
TwoFactorAuthenticationFilter {
 
     public InsecureTwoFactorAuthenticationFilter() {
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
index ffdc2ed33..b86182b80 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TenantAwareBasicAuthenticationFilter.java
@@ -18,13 +18,15 @@
  */
 package org.apache.fineract.infrastructure.security.filter;
 
-import java.io.IOException;
-import java.time.LocalDate;
-import java.util.HashMap;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.util.HashMap;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.time.StopWatch;
 import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
 import 
org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
@@ -39,16 +41,14 @@ import 
org.apache.fineract.infrastructure.security.exception.InvalidTenantIdenti
 import 
org.apache.fineract.infrastructure.security.service.BasicAuthTenantDetailsService;
 import org.apache.fineract.notification.service.UserNotificationService;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import org.springframework.security.authentication.AuthenticationManager;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.web.AuthenticationEntryPoint;
 import 
org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
+import org.springframework.security.web.util.matcher.AnyRequestMatcher;
+import org.springframework.security.web.util.matcher.RequestMatcher;
 
 /**
  * A customised version of spring security's {@link BasicAuthenticationFilter}.
@@ -63,36 +63,32 @@ import 
org.springframework.security.web.authentication.www.BasicAuthenticationFi
  * If multi-tenant and basic auth credentials are invalid, a http error 
response is returned.
  */
 
-@ConditionalOnProperty("fineract.security.basicauth.enabled")
+@Slf4j
 public class TenantAwareBasicAuthenticationFilter extends 
BasicAuthenticationFilter {
 
     private static boolean firstRequestProcessed = false;
-    private static final Logger LOG = 
LoggerFactory.getLogger(TenantAwareBasicAuthenticationFilter.class);
-
-    @Autowired
-    private ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
-
-    @Autowired
-    private ConfigurationDomainService configurationDomainService;
-
-    @Autowired
-    private CacheWritePlatformService cacheWritePlatformService;
-
-    @Autowired
-    private UserNotificationService userNotificationService;
-
-    @Autowired
-    private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
-
-    @Autowired
-    private BusinessDateReadPlatformService businessDateReadPlatformService;
+    private final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
+    private final ConfigurationDomainService configurationDomainService;
+    private final CacheWritePlatformService cacheWritePlatformService;
+    private final UserNotificationService userNotificationService;
+    private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
+    private final BusinessDateReadPlatformService 
businessDateReadPlatformService;
 
     private final String tenantRequestHeader = "Fineract-Platform-TenantId";
     private final boolean exceptionIfHeaderMissing = true;
 
+    @Setter
+    private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
+
     public TenantAwareBasicAuthenticationFilter(final AuthenticationManager 
authenticationManager,
-            final AuthenticationEntryPoint authenticationEntryPoint) {
+                                                final AuthenticationEntryPoint 
authenticationEntryPoint, ToApiJsonSerializer<PlatformRequestLog> 
toApiJsonSerializer, ConfigurationDomainService configurationDomainService, 
CacheWritePlatformService cacheWritePlatformService, UserNotificationService 
userNotificationService, BasicAuthTenantDetailsService 
basicAuthTenantDetailsService, BusinessDateReadPlatformService 
businessDateReadPlatformService) {
         super(authenticationManager, authenticationEntryPoint);
+        this.toApiJsonSerializer = toApiJsonSerializer;
+        this.configurationDomainService = configurationDomainService;
+        this.cacheWritePlatformService = cacheWritePlatformService;
+        this.userNotificationService = userNotificationService;
+        this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
+        this.businessDateReadPlatformService = businessDateReadPlatformService;
     }
 
     @Override
@@ -108,48 +104,49 @@ public class TenantAwareBasicAuthenticationFilter extends 
BasicAuthenticationFil
                 // ignore to allow 'preflight' requests from AJAX applications
                 // in different origin (domain name)
             } else {
+                if (requestMatcher.matches(request)) {
+                    String tenantIdentifier = 
request.getHeader(this.tenantRequestHeader);
 
-                String tenantIdentifier = 
request.getHeader(this.tenantRequestHeader);
-
-                if 
(org.apache.commons.lang3.StringUtils.isBlank(tenantIdentifier)) {
-                    tenantIdentifier = 
request.getParameter("tenantIdentifier");
-                }
-
-                if (tenantIdentifier == null && this.exceptionIfHeaderMissing) 
{
-                    throw new InvalidTenantIdentifierException("No tenant 
identifier found: Add request header of '"
-                            + this.tenantRequestHeader + "' or add the 
parameter 'tenantIdentifier' to query string of request URL.");
-                }
+                    if 
(org.apache.commons.lang3.StringUtils.isBlank(tenantIdentifier)) {
+                        tenantIdentifier = 
request.getParameter("tenantIdentifier");
+                    }
 
-                String pathInfo = request.getRequestURI();
-                boolean isReportRequest = false;
-                if (pathInfo != null && pathInfo.contains("report")) {
-                    isReportRequest = true;
-                }
-                final FineractPlatformTenant tenant = 
this.basicAuthTenantDetailsService.loadTenantById(tenantIdentifier, 
isReportRequest);
-                ThreadLocalContextUtil.setTenant(tenant);
-                HashMap<BusinessDateType, LocalDate> businessDates = 
this.businessDateReadPlatformService.getBusinessDates();
-                ThreadLocalContextUtil.setBusinessDates(businessDates);
-                String authToken = request.getHeader("Authorization");
-
-                if (authToken != null && authToken.startsWith("Basic ")) {
-                    
ThreadLocalContextUtil.setAuthToken(authToken.replaceFirst("Basic ", ""));
-                }
+                    if (tenantIdentifier == null && 
this.exceptionIfHeaderMissing) {
+                        throw new InvalidTenantIdentifierException("No tenant 
identifier found: Add request header of '"
+                                + this.tenantRequestHeader + "' or add the 
parameter 'tenantIdentifier' to query string of request URL.");
+                    }
 
-                if (!firstRequestProcessed) {
-                    final String baseUrl = 
request.getRequestURL().toString().replace(request.getPathInfo(), "/");
-                    System.setProperty("baseUrl", baseUrl);
+                    String pathInfo = request.getRequestURI();
+                    boolean isReportRequest = false;
+                    if (pathInfo != null && pathInfo.contains("report")) {
+                        isReportRequest = true;
+                    }
+                    final FineractPlatformTenant tenant = 
this.basicAuthTenantDetailsService.loadTenantById(tenantIdentifier, 
isReportRequest);
+                    ThreadLocalContextUtil.setTenant(tenant);
+                    HashMap<BusinessDateType, LocalDate> businessDates = 
this.businessDateReadPlatformService.getBusinessDates();
+                    ThreadLocalContextUtil.setBusinessDates(businessDates);
+                    String authToken = request.getHeader("Authorization");
+
+                    if (authToken != null && authToken.startsWith("Basic ")) {
+                        
ThreadLocalContextUtil.setAuthToken(authToken.replaceFirst("Basic ", ""));
+                    }
 
-                    final boolean ehcacheEnabled = 
this.configurationDomainService.isEhcacheEnabled();
-                    if (ehcacheEnabled) {
-                        
this.cacheWritePlatformService.switchToCache(CacheType.SINGLE_NODE);
-                    } else {
-                        
this.cacheWritePlatformService.switchToCache(CacheType.NO_CACHE);
+                    if (!firstRequestProcessed) {
+                        final String baseUrl = 
request.getRequestURL().toString().replace(request.getPathInfo(), "/");
+                        System.setProperty("baseUrl", baseUrl);
+
+                        final boolean ehcacheEnabled = 
this.configurationDomainService.isEhcacheEnabled();
+                        if (ehcacheEnabled) {
+                            
this.cacheWritePlatformService.switchToCache(CacheType.SINGLE_NODE);
+                        } else {
+                            
this.cacheWritePlatformService.switchToCache(CacheType.NO_CACHE);
+                        }
+                        
TenantAwareBasicAuthenticationFilter.firstRequestProcessed = true;
                     }
-                    TenantAwareBasicAuthenticationFilter.firstRequestProcessed 
= true;
                 }
-            }
 
-            super.doFilterInternal(request, response, filterChain);
+                super.doFilterInternal(request, response, filterChain);
+            }
         } catch (final InvalidTenantIdentifierException e) {
             // deal with exception at low level
             SecurityContextHolder.getContext().setAuthentication(null);
@@ -160,7 +157,7 @@ public class TenantAwareBasicAuthenticationFilter extends 
BasicAuthenticationFil
             ThreadLocalContextUtil.reset();
             task.stop();
             final PlatformRequestLog log = PlatformRequestLog.from(task, 
request);
-            LOG.debug("{}", this.toApiJsonSerializer.serialize(log));
+            TenantAwareBasicAuthenticationFilter.log.debug("{}", 
this.toApiJsonSerializer.serialize(log));
         }
     }
 
diff --git 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java
 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java
index f025df54f..6c6d382a5 100644
--- 
a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java
+++ 
b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/filter/TwoFactorAuthenticationFilter.java
@@ -18,23 +18,22 @@
  */
 package org.apache.fineract.infrastructure.security.filter;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
 import jakarta.servlet.FilterChain;
 import jakarta.servlet.ServletException;
 import jakarta.servlet.ServletRequest;
 import jakarta.servlet.ServletResponse;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
 import 
org.apache.fineract.infrastructure.security.constants.TwoFactorConstants;
 import 
org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
 import org.apache.fineract.infrastructure.security.domain.TFAccessToken;
 import org.apache.fineract.infrastructure.security.service.TwoFactorService;
 import org.apache.fineract.useradministration.domain.AppUser;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
 import 
org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.Authentication;
 import org.springframework.security.core.GrantedAuthority;
@@ -42,7 +41,6 @@ import 
org.springframework.security.core.authority.SimpleGrantedAuthority;
 import org.springframework.security.core.context.SecurityContext;
 import org.springframework.security.core.context.SecurityContextHolder;
 import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.stereotype.Service;
 import org.springframework.web.filter.GenericFilterBean;
 
 /**
@@ -56,17 +54,11 @@ import org.springframework.web.filter.GenericFilterBean;
  * An authenticated platform user with permission 'BYPASS_TWOFACTOR' will 
always be granted 'TWOFACTOR_AUTHENTICATED'
  * authority regardless of the value of the 'Fineract-Platform-TFA-Token' 
header.
  */
-@Service
-@ConditionalOnProperty("fineract.security.2fa.enabled")
+@RequiredArgsConstructor
 public class TwoFactorAuthenticationFilter extends GenericFilterBean {
 
     private final TwoFactorService twoFactorService;
 
-    @Autowired
-    public TwoFactorAuthenticationFilter(TwoFactorService twoFactorService) {
-        this.twoFactorService = twoFactorService;
-    }
-
     @Override
     public void doFilter(ServletRequest req, ServletResponse res, FilterChain 
chain) throws IOException, ServletException {
 
diff --git a/fineract-provider/src/main/resources/META-INF/orm.xml 
b/fineract-provider/src/main/resources/META-INF/orm.xml
index b54608dee..4f05f84e6 100644
--- a/fineract-provider/src/main/resources/META-INF/orm.xml
+++ b/fineract-provider/src/main/resources/META-INF/orm.xml
@@ -21,18 +21,18 @@
 -->
 
 
-<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm";
-    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
-    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm 
http://java.sun.com/xml/ns/persistence/orm_2_0.xsd";
-    version="2.0">
+<entity-mappings xmlns="https://jakarta.ee/xml/ns/persistence/orm";
+                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+                 xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/orm
+          https://jakarta.ee/xml/ns/persistence/orm/orm_3_0.xsd"; version="3.0">
 
     <persistence-unit-metadata>
         <persistence-unit-defaults>
             <delimited-identifiers/>
-<!--            <entity-listeners>-->
-<!--                <entity-listener-->
-<!--                    
class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />-->
-<!--            </entity-listeners>-->
+            <entity-listeners>
+                <entity-listener
+                        
class="org.springframework.data.jpa.domain.support.AuditingEntityListener"/>
+            </entity-listeners>
         </persistence-unit-defaults>
     </persistence-unit-metadata>
 
diff --git a/integration-tests/dependencies.gradle 
b/integration-tests/dependencies.gradle
index b46b15b7a..ee05c9657 100644
--- a/integration-tests/dependencies.gradle
+++ b/integration-tests/dependencies.gradle
@@ -42,6 +42,8 @@ dependencies {
         exclude group: 'org.apache.sling'
         exclude group: 'com.sun.xml.bind'
     }
+    testImplementation 'org.apache.groovy:groovy-xml'
+    testImplementation 'org.apache.groovy:groovy-json'
     testImplementation 'org.awaitility:awaitility'
 
     testCompileOnly 'org.projectlombok:lombok'
diff --git 
a/integration-tests/src/integrationTest/resources/bulkimport/importhandler/loan/Loan.xls
 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/loan/Loan.xls
new file mode 100644
index 000000000..a7c87b5bd
Binary files /dev/null and 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/loan/Loan.xls
 differ
diff --git 
a/integration-tests/src/integrationTest/resources/bulkimport/importhandler/office/Office.xls
 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/office/Office.xls
new file mode 100644
index 000000000..3a63e1221
Binary files /dev/null and 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/office/Office.xls
 differ
diff --git 
a/integration-tests/src/integrationTest/resources/bulkimport/importhandler/savings/Savings.xls
 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/savings/Savings.xls
new file mode 100644
index 000000000..ec42864d5
Binary files /dev/null and 
b/integration-tests/src/integrationTest/resources/bulkimport/importhandler/savings/Savings.xls
 differ

Reply via email to