FINERACT-1724: EclipseLink upgrade fixes + Spring Security chain fixes
This commit is contained in:
committed by
Arnold Gálovics
parent
abb5d4abb5
commit
a7d5f834d5
+1
-1
@@ -55,7 +55,7 @@ buildscript {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.bmuschko:gradle-cargo-plugin:2.9.0'
|
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 'jakarta.ws.rs:jakarta.ws.rs-api:3.1.0'
|
||||||
classpath 'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.3.0'
|
classpath 'com.google.cloud.tools:jib-layer-filter-extension-gradle:0.3.0'
|
||||||
classpath 'org.apache.commons:commons-lang3:3.12.0'
|
classpath 'org.apache.commons:commons-lang3:3.12.0'
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ dependencyManagement {
|
|||||||
dependency 'org.codehaus.janino:janino:3.1.9'
|
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.guava:guava:31.1-jre'
|
||||||
dependency 'com.google.code.gson:gson:2.10.1'
|
dependency 'com.google.code.gson:gson:2.10.1'
|
||||||
dependency 'com.google.truth:truth:1.1.3'
|
dependency 'com.google.truth:truth:1.1.3'
|
||||||
@@ -64,6 +64,7 @@ dependencyManagement {
|
|||||||
dependency 'com.github.librepdf:openpdf:1.3.30'
|
dependency 'com.github.librepdf:openpdf:1.3.30'
|
||||||
dependency ('org.mnode.ical4j:ical4j:3.2.11') {
|
dependency ('org.mnode.ical4j:ical4j:3.2.11') {
|
||||||
exclude 'com.sun.mail:javax.mail'
|
exclude 'com.sun.mail:javax.mail'
|
||||||
|
exclude 'org.codehaus.groovy:groovy'
|
||||||
}
|
}
|
||||||
dependency 'org.apache.commons:commons-csv:1.10.0'
|
dependency 'org.apache.commons:commons-csv:1.10.0'
|
||||||
dependency 'org.quartz-scheduler:quartz:2.3.2'
|
dependency 'org.quartz-scheduler:quartz:2.3.2'
|
||||||
@@ -233,6 +234,8 @@ dependencyManagement {
|
|||||||
entry 'json-path'
|
entry 'json-path'
|
||||||
entry 'xml-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:1.5.4.Final'
|
||||||
dependency 'org.mapstruct:mapstruct-processor:1.5.4.Final'
|
dependency 'org.mapstruct:mapstruct-processor:1.5.4.Final'
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
com.acme.fineract.event.starter.AcmeEventAutoConfiguration
|
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
com.acme.fineract.event.starter.AcmeEventAutoConfiguration
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
com.acme.fineract.loan.starter.AcmeLoanAutoConfiguration
|
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
com.acme.fineract.loan.starter.AcmeLoanAutoConfiguration
|
||||||
-1
@@ -1,2 +1 @@
|
|||||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
|
||||||
com.acme.fineract.portfolio.note.starter.AcmeNoteAutoConfiguration
|
com.acme.fineract.portfolio.note.starter.AcmeNoteAutoConfiguration
|
||||||
+1
@@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.core.boot;
|
|||||||
public final class FineractProfiles {
|
public final class FineractProfiles {
|
||||||
|
|
||||||
public static final String LIQUIBASE_ONLY = "liquibase-only";
|
public static final String LIQUIBASE_ONLY = "liquibase-only";
|
||||||
|
public static final String DIAGNOSTICS = "diagnostics";
|
||||||
|
|
||||||
private FineractProfiles() {}
|
private FineractProfiles() {}
|
||||||
}
|
}
|
||||||
|
|||||||
+36
@@ -57,6 +57,7 @@ public class FineractProperties {
|
|||||||
|
|
||||||
private FineractQueryProperties query;
|
private FineractQueryProperties query;
|
||||||
private FineractApiProperties api;
|
private FineractApiProperties api;
|
||||||
|
private FineractSecurityProperties security;
|
||||||
|
|
||||||
private FineractNotificationProperties notification;
|
private FineractNotificationProperties notification;
|
||||||
|
|
||||||
@@ -352,6 +353,41 @@ public class FineractProperties {
|
|||||||
private boolean errorNotFoundFail;
|
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
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
public static class FineractTransactionProcessorItemProperties {
|
public static class FineractTransactionProcessorItemProperties {
|
||||||
|
|||||||
+43
-28
@@ -25,15 +25,21 @@ import static org.springframework.security.authorization.AuthorityAuthorizationM
|
|||||||
import static org.springframework.security.authorization.AuthorizationManagers.allOf;
|
import static org.springframework.security.authorization.AuthorizationManagers.allOf;
|
||||||
|
|
||||||
import java.util.Collection;
|
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.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.FineractJwtAuthenticationToken;
|
||||||
|
import org.apache.fineract.infrastructure.security.data.PlatformRequestLog;
|
||||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareTenantIdentifierFilter;
|
import org.apache.fineract.infrastructure.security.filter.TenantAwareTenantIdentifierFilter;
|
||||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
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.TenantAwareJpaPlatformUserDetailsService;
|
||||||
|
import org.apache.fineract.infrastructure.security.service.TwoFactorService;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.core.convert.converter.Converter;
|
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.authentication.www.BasicAuthenticationFilter;
|
||||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
||||||
|
|
||||||
@Configuration
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnProperty("fineract.security.oauth.enabled")
|
@ConditionalOnProperty("fineract.security.oauth.enabled")
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
public class OAuth2SecurityConfig {
|
public class OAuth2SecurityConfig {
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TenantAwareTenantIdentifierFilter tenantAwareTenantIdentifierFilter;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantAwareJpaPlatformUserDetailsService userDetailsService;
|
private TenantAwareJpaPlatformUserDetailsService userDetailsService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ServerProperties serverProperties;
|
private ServerProperties serverProperties;
|
||||||
|
|
||||||
private static final JwtGrantedAuthoritiesConverter jwtGrantedAuthoritiesConverter = new JwtGrantedAuthoritiesConverter();
|
@Autowired
|
||||||
|
private TwoFactorService twoFactorService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
||||||
|
|
||||||
|
@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
|
@Bean
|
||||||
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
||||||
@@ -90,26 +107,40 @@ public class OAuth2SecurityConfig {
|
|||||||
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
||||||
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
|
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (serverProperties.getSsl().isEnabled()) {
|
||||||
|
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||||
|
}
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SecurityFilterChain FilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
||||||
http //
|
http //
|
||||||
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
|
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
|
||||||
.exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
|
.exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
|
||||||
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
|
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
|
||||||
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
|
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
|
||||||
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
|
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
|
||||||
.addFilterAfter(tenantAwareTenantIdentifierFilter, SecurityContextHolderFilter.class) //
|
.addFilterAfter(tenantAwareTenantIdentifierFilter(), SecurityContextHolderFilter.class) //
|
||||||
.addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class); //
|
.addFilterAfter(twoFactorAuthenticationFilter(), BasicAuthenticationFilter.class); //
|
||||||
|
|
||||||
if (serverProperties.getSsl().isEnabled()) {
|
if (serverProperties.getSsl().isEnabled()) {
|
||||||
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||||
}
|
}
|
||||||
|
|
||||||
return http.build();
|
return http.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TenantAwareTenantIdentifierFilter tenantAwareTenantIdentifierFilter() {
|
||||||
|
return new TenantAwareTenantIdentifierFilter(basicAuthTenantDetailsService, toApiJsonSerializer, configurationDomainService, cacheWritePlatformService, businessDateReadPlatformService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TwoFactorAuthenticationFilter twoFactorAuthenticationFilter() {
|
||||||
|
return new TwoFactorAuthenticationFilter(twoFactorService);
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public PasswordEncoder passwordEncoder() {
|
public PasswordEncoder passwordEncoder() {
|
||||||
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+122
-45
@@ -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.AuthorityAuthorizationManager.hasAuthority;
|
||||||
import static org.springframework.security.authorization.AuthorizationManagers.allOf;
|
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.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.instancemode.filter.FineractInstanceModeApiFilter;
|
||||||
import org.apache.fineract.infrastructure.jobs.filter.LoanCOBApiFilter;
|
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.InsecureTwoFactorAuthenticationFilter;
|
||||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
|
import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
|
||||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
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.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.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.springframework.boot.autoconfigure.web.ServerProperties;
|
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.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -48,25 +69,19 @@ import org.springframework.security.crypto.password.PasswordEncoder;
|
|||||||
import org.springframework.security.web.SecurityFilterChain;
|
import org.springframework.security.web.SecurityFilterChain;
|
||||||
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
import org.springframework.security.web.access.ExceptionTranslationFilter;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.security.web.context.SecurityContextHolderFilter;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
@Configuration
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnProperty("fineract.security.basicauth.enabled")
|
@ConditionalOnProperty("fineract.security.basicauth.enabled")
|
||||||
@EnableMethodSecurity
|
@EnableMethodSecurity
|
||||||
public class SecurityConfig {
|
public class SecurityConfig {
|
||||||
|
@Autowired
|
||||||
|
private ApplicationContext applicationContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private TenantAwareJpaPlatformUserDetailsService userDetailsService;
|
private TenantAwareJpaPlatformUserDetailsService userDetailsService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private FineractInstanceModeApiFilter fineractInstanceModeApiFilter;
|
|
||||||
@Autowired
|
|
||||||
private LoanCOBApiFilter loanCOBApiFilter;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FineractProperties fineractProperties;
|
private FineractProperties fineractProperties;
|
||||||
|
|
||||||
@@ -74,8 +89,40 @@ public class SecurityConfig {
|
|||||||
private ServerProperties serverProperties;
|
private ServerProperties serverProperties;
|
||||||
|
|
||||||
@Autowired
|
@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
|
@Bean
|
||||||
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
|
||||||
@@ -93,20 +140,7 @@ public class SecurityConfig {
|
|||||||
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
|
||||||
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
|
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"))); //
|
||||||
}) //
|
}) //
|
||||||
.httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint())); //
|
.httpBasic((httpBasic) -> httpBasic.authenticationEntryPoint(basicAuthenticationEntryPoint()));
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
||||||
http //
|
|
||||||
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
|
|
||||||
.sessionManagement((smc) -> smc.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) //
|
|
||||||
.addFilterAfter(fineractInstanceModeApiFilter, SecurityContextHolderFilter.class) //
|
|
||||||
.addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) //
|
|
||||||
.addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class) //
|
|
||||||
.addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class) //
|
|
||||||
.addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class); //
|
|
||||||
|
|
||||||
if (serverProperties.getSsl().isEnabled()) {
|
if (serverProperties.getSsl().isEnabled()) {
|
||||||
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
|
||||||
@@ -115,8 +149,68 @@ public class SecurityConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
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(requestResponseFilter(), ExceptionTranslationFilter.class)
|
||||||
|
.addFilterAfter(correlationHeaderFilter(), RequestResponseFilter.class)
|
||||||
|
.addFilterAfter(responseCorsFilter(), CorrelationHeaderFilter.class) //
|
||||||
|
.addFilterAfter(fineractInstanceModeApiFilter(), ResponseCorsFilter.class) //
|
||||||
|
.addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) //
|
||||||
|
.addFilterAfter(loanCOBApiFilter(), TenantAwareBasicAuthenticationFilter.class) //
|
||||||
|
.addFilterAfter(idempotencyStoreFilter(), LoanCOBApiFilter.class); //
|
||||||
|
|
||||||
|
if (fineractProperties.getSecurity().getTwoFactor().isEnabled()) {
|
||||||
|
http.addFilterAfter(twoFactorAuthenticationFilter(), FineractInstanceModeApiFilter.class);
|
||||||
|
} else {
|
||||||
|
http.addFilterAfter(insecureTwoFactorAuthenticationFilter(), FineractInstanceModeApiFilter.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
return http.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
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
|
@Bean
|
||||||
@@ -145,21 +239,4 @@ public class SecurityConfig {
|
|||||||
providerManager.setEraseCredentialsAfterAuthentication(false);
|
providerManager.setEraseCredentialsAfterAuthentication(false);
|
||||||
return providerManager;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
-36
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+2
-1
@@ -20,6 +20,7 @@ package org.apache.fineract.infrastructure.core.diagnostics.jpa;
|
|||||||
|
|
||||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||||
import jakarta.persistence.EntityManagerFactory;
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
import org.apache.fineract.infrastructure.core.boot.FineractProfiles;
|
||||||
import org.eclipse.persistence.internal.jpa.EntityManagerImpl;
|
import org.eclipse.persistence.internal.jpa.EntityManagerImpl;
|
||||||
import org.eclipse.persistence.sessions.changesets.UnitOfWorkChangeSet;
|
import org.eclipse.persistence.sessions.changesets.UnitOfWorkChangeSet;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
@@ -38,7 +39,7 @@ import org.springframework.stereotype.Component;
|
|||||||
* <br>
|
* <br>
|
||||||
* To enable this, run Fineract with the <b>diagnostics</b> profile.
|
* To enable this, run Fineract with the <b>diagnostics</b> profile.
|
||||||
*/
|
*/
|
||||||
@Profile("diagnostics")
|
@Profile(FineractProfiles.DIAGNOSTICS)
|
||||||
@Component
|
@Component
|
||||||
public class DiagnosticsEntityManager implements ApplicationContextAware {
|
public class DiagnosticsEntityManager implements ApplicationContextAware {
|
||||||
|
|
||||||
|
|||||||
+81
@@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-3
@@ -19,23 +19,21 @@
|
|||||||
|
|
||||||
package org.apache.fineract.infrastructure.core.filters;
|
package org.apache.fineract.infrastructure.core.filters;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
import org.apache.fineract.infrastructure.core.service.MDCWrapper;
|
import org.apache.fineract.infrastructure.core.service.MDCWrapper;
|
||||||
import org.apache.fineract.infrastructure.security.utils.LogParameterEscapeUtil;
|
import org.apache.fineract.infrastructure.security.utils.LogParameterEscapeUtil;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
|
||||||
public class CorrelationHeaderFilter extends OncePerRequestFilter {
|
public class CorrelationHeaderFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
public static final String CORRELATION_ID_KEY = "correlationId";
|
public static final String CORRELATION_ID_KEY = "correlationId";
|
||||||
|
|||||||
+3
-5
@@ -18,14 +18,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.core.filters;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.ws.rs.core.UriInfo;
|
import jakarta.ws.rs.core.UriInfo;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.mutable.Mutable;
|
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.config.FineractProperties;
|
||||||
import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
|
import org.apache.fineract.infrastructure.core.domain.FineractRequestContextHolder;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
import org.springframework.web.util.ContentCachingResponseWrapper;
|
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
|
||||||
public class IdempotencyStoreFilter extends OncePerRequestFilter implements BatchFilter {
|
public class IdempotencyStoreFilter extends OncePerRequestFilter implements BatchFilter {
|
||||||
|
|
||||||
private final CommandSourceRepository commandSourceRepository;
|
private final CommandSourceRepository commandSourceRepository;
|
||||||
|
|||||||
+1
-3
@@ -19,19 +19,17 @@
|
|||||||
|
|
||||||
package org.apache.fineract.infrastructure.core.filters;
|
package org.apache.fineract.infrastructure.core.filters;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
|
||||||
public class RequestResponseFilter extends OncePerRequestFilter {
|
public class RequestResponseFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+14
-19
@@ -18,36 +18,31 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.core.filters;
|
package org.apache.fineract.infrastructure.core.filters;
|
||||||
|
|
||||||
import jakarta.ws.rs.container.ContainerRequestContext;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.ws.rs.container.ContainerResponseContext;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.ws.rs.container.ContainerResponseFilter;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.ws.rs.ext.Provider;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.context.annotation.Scope;
|
import java.io.IOException;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.util.StringUtils;
|
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
|
* Filter that returns a response with headers that allows for Cross-Origin Requests (CORs) to be performed against the
|
||||||
* platform API.
|
* platform API.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@Provider
|
public class ResponseCorsFilter extends OncePerRequestFilter {
|
||||||
@Component
|
|
||||||
@Scope("singleton")
|
|
||||||
public class ResponseCorsFilter implements ContainerResponseFilter {
|
|
||||||
|
|
||||||
@Override
|
@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", "*");
|
final String reqHead = request.getHeader("Access-Control-Request-Headers");
|
||||||
// .header("Access-Control-Expose-Headers",
|
|
||||||
// "Fineract-Platform-TenantId")
|
|
||||||
response.getHeaders().add("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
|
|
||||||
|
|
||||||
final String reqHead = request.getHeaders().getFirst("Access-Control-Request-Headers");
|
if (StringUtils.hasText(reqHead)) {
|
||||||
|
response.addHeader("Access-Control-Allow-Headers", reqHead);
|
||||||
if (null != reqHead && StringUtils.hasText(reqHead)) {
|
|
||||||
response.getHeaders().add("Access-Control-Allow-Headers", reqHead);
|
|
||||||
}
|
}
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
@Configuration
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ApplicationPath("/api")
|
@ApplicationPath("/api")
|
||||||
public class JerseyConfig extends ResourceConfig {
|
public class JerseyConfig extends ResourceConfig {
|
||||||
|
|
||||||
|
|||||||
+3
-5
@@ -21,23 +21,21 @@ package org.apache.fineract.infrastructure.instancemode.filter;
|
|||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
import static org.apache.fineract.infrastructure.instancemode.filter.FineractInstanceModeApiFilter.ExceptionListItem.item;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.ws.rs.HttpMethod;
|
import jakarta.ws.rs.HttpMethod;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Function;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class FineractInstanceModeApiFilter extends OncePerRequestFilter {
|
public class FineractInstanceModeApiFilter extends OncePerRequestFilter {
|
||||||
|
|
||||||
|
|||||||
+4
-6
@@ -22,6 +22,10 @@ import static org.apache.fineract.batch.command.CommandStrategyUtils.isRelativeU
|
|||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import io.github.resilience4j.core.functions.Either;
|
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.io.IOException;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -29,10 +33,6 @@ import java.util.Collections;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.regex.Pattern;
|
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 lombok.RequiredArgsConstructor;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
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.fineract.useradministration.exception.UnAuthenticatedUserException;
|
||||||
import org.apache.http.HttpStatus;
|
import org.apache.http.HttpStatus;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
@Component
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchRequestPreprocessor {
|
public class LoanCOBApiFilter extends OncePerRequestFilter implements BatchRequestPreprocessor {
|
||||||
|
|
||||||
|
|||||||
+4
-8
@@ -18,16 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.security.filter;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
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.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
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.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
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.
|
* A dummy {@link TwoFactorAuthenticationFilter} filter used when 'twofactor' environment profile is not active.
|
||||||
*
|
*
|
||||||
* This filter adds 'TWOFACTOR_AUTHENTICATED' authority to every authenticated platform user.
|
* 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 class InsecureTwoFactorAuthenticationFilter extends TwoFactorAuthenticationFilter {
|
||||||
|
|
||||||
public InsecureTwoFactorAuthenticationFilter() {
|
public InsecureTwoFactorAuthenticationFilter() {
|
||||||
|
|||||||
+65
-68
@@ -18,13 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.security.filter;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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.commons.lang3.time.StopWatch;
|
||||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
|
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.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||||
import org.apache.fineract.notification.service.UserNotificationService;
|
import org.apache.fineract.notification.service.UserNotificationService;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
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.AuthenticationManager;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
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}.
|
* 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.
|
* 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 {
|
public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFilter {
|
||||||
|
|
||||||
private static boolean firstRequestProcessed = false;
|
private static boolean firstRequestProcessed = false;
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(TenantAwareBasicAuthenticationFilter.class);
|
private final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
|
||||||
|
private final ConfigurationDomainService configurationDomainService;
|
||||||
@Autowired
|
private final CacheWritePlatformService cacheWritePlatformService;
|
||||||
private ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
|
private final UserNotificationService userNotificationService;
|
||||||
|
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
||||||
@Autowired
|
private final BusinessDateReadPlatformService businessDateReadPlatformService;
|
||||||
private ConfigurationDomainService configurationDomainService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private CacheWritePlatformService cacheWritePlatformService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private UserNotificationService userNotificationService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private BusinessDateReadPlatformService businessDateReadPlatformService;
|
|
||||||
|
|
||||||
private final String tenantRequestHeader = "Fineract-Platform-TenantId";
|
private final String tenantRequestHeader = "Fineract-Platform-TenantId";
|
||||||
private final boolean exceptionIfHeaderMissing = true;
|
private final boolean exceptionIfHeaderMissing = true;
|
||||||
|
|
||||||
|
@Setter
|
||||||
|
private RequestMatcher requestMatcher = AnyRequestMatcher.INSTANCE;
|
||||||
|
|
||||||
public TenantAwareBasicAuthenticationFilter(final AuthenticationManager authenticationManager,
|
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);
|
super(authenticationManager, authenticationEntryPoint);
|
||||||
|
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||||
|
this.configurationDomainService = configurationDomainService;
|
||||||
|
this.cacheWritePlatformService = cacheWritePlatformService;
|
||||||
|
this.userNotificationService = userNotificationService;
|
||||||
|
this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
|
||||||
|
this.businessDateReadPlatformService = businessDateReadPlatformService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -108,48 +104,49 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
|||||||
// ignore to allow 'preflight' requests from AJAX applications
|
// ignore to allow 'preflight' requests from AJAX applications
|
||||||
// in different origin (domain name)
|
// in different origin (domain name)
|
||||||
} else {
|
} 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 (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.");
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (!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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.doFilterInternal(request, response, filterChain);
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (!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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
super.doFilterInternal(request, response, filterChain);
|
||||||
|
}
|
||||||
} catch (final InvalidTenantIdentifierException e) {
|
} catch (final InvalidTenantIdentifierException e) {
|
||||||
// deal with exception at low level
|
// deal with exception at low level
|
||||||
SecurityContextHolder.getContext().setAuthentication(null);
|
SecurityContextHolder.getContext().setAuthentication(null);
|
||||||
@@ -160,7 +157,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
|||||||
ThreadLocalContextUtil.reset();
|
ThreadLocalContextUtil.reset();
|
||||||
task.stop();
|
task.stop();
|
||||||
final PlatformRequestLog log = PlatformRequestLog.from(task, request);
|
final PlatformRequestLog log = PlatformRequestLog.from(task, request);
|
||||||
LOG.debug("{}", this.toApiJsonSerializer.serialize(log));
|
TenantAwareBasicAuthenticationFilter.log.debug("{}", this.toApiJsonSerializer.serialize(log));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-14
@@ -18,23 +18,22 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.infrastructure.security.filter;
|
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.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
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.constants.TwoFactorConstants;
|
||||||
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
import org.apache.fineract.infrastructure.security.data.FineractJwtAuthenticationToken;
|
||||||
import org.apache.fineract.infrastructure.security.domain.TFAccessToken;
|
import org.apache.fineract.infrastructure.security.domain.TFAccessToken;
|
||||||
import org.apache.fineract.infrastructure.security.service.TwoFactorService;
|
import org.apache.fineract.infrastructure.security.service.TwoFactorService;
|
||||||
import org.apache.fineract.useradministration.domain.AppUser;
|
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.authentication.UsernamePasswordAuthenticationToken;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
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.SecurityContext;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.web.filter.GenericFilterBean;
|
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'
|
* 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.
|
* authority regardless of the value of the 'Fineract-Platform-TFA-Token' header.
|
||||||
*/
|
*/
|
||||||
@Service
|
@RequiredArgsConstructor
|
||||||
@ConditionalOnProperty("fineract.security.2fa.enabled")
|
|
||||||
public class TwoFactorAuthenticationFilter extends GenericFilterBean {
|
public class TwoFactorAuthenticationFilter extends GenericFilterBean {
|
||||||
|
|
||||||
private final TwoFactorService twoFactorService;
|
private final TwoFactorService twoFactorService;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public TwoFactorAuthenticationFilter(TwoFactorService twoFactorService) {
|
|
||||||
this.twoFactorService = twoFactorService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||||
|
|
||||||
|
|||||||
@@ -21,18 +21,18 @@
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
|
|
||||||
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
|
<entity-mappings xmlns="https://jakarta.ee/xml/ns/persistence/orm"
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
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"
|
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence/orm
|
||||||
version="2.0">
|
https://jakarta.ee/xml/ns/persistence/orm/orm_3_0.xsd" version="3.0">
|
||||||
|
|
||||||
<persistence-unit-metadata>
|
<persistence-unit-metadata>
|
||||||
<persistence-unit-defaults>
|
<persistence-unit-defaults>
|
||||||
<delimited-identifiers/>
|
<delimited-identifiers/>
|
||||||
<!-- <entity-listeners>-->
|
<entity-listeners>
|
||||||
<!-- <entity-listener-->
|
<entity-listener
|
||||||
<!-- class="org.springframework.data.jpa.domain.support.AuditingEntityListener" />-->
|
class="org.springframework.data.jpa.domain.support.AuditingEntityListener"/>
|
||||||
<!-- </entity-listeners>-->
|
</entity-listeners>
|
||||||
</persistence-unit-defaults>
|
</persistence-unit-defaults>
|
||||||
</persistence-unit-metadata>
|
</persistence-unit-metadata>
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ dependencies {
|
|||||||
exclude group: 'org.apache.sling'
|
exclude group: 'org.apache.sling'
|
||||||
exclude group: 'com.sun.xml.bind'
|
exclude group: 'com.sun.xml.bind'
|
||||||
}
|
}
|
||||||
|
testImplementation 'org.apache.groovy:groovy-xml'
|
||||||
|
testImplementation 'org.apache.groovy:groovy-json'
|
||||||
testImplementation 'org.awaitility:awaitility'
|
testImplementation 'org.awaitility:awaitility'
|
||||||
|
|
||||||
testCompileOnly 'org.projectlombok:lombok'
|
testCompileOnly 'org.projectlombok:lombok'
|
||||||
|
|||||||
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Reference in New Issue
Block a user