FINERACT-1724: Further upgrades

This commit is contained in:
Arnold Galovics
2023-06-06 11:45:08 +02:00
committed by Arnold Gálovics
parent bc4b707646
commit abb5d4abb5
14 changed files with 154 additions and 40 deletions
+1
View File
@@ -28,6 +28,7 @@ dependencies {
implementation(
'org.springframework.boot:spring-boot-starter-web',
'org.springframework.boot:spring-boot-starter-security',
'org.springframework.boot:spring-boot-starter-validation',
'jakarta.ws.rs:jakarta.ws.rs-api',
'org.glassfish.jersey.media:jersey-media-multipart',
+4 -4
View File
@@ -155,10 +155,10 @@ dependencies {
driver 'mysql:mysql-connector-java:8.0.32'
}
//URLClassLoader loader = GroovyObject.class.classLoader
//configurations.driver.each {File file ->
// loader.addURL(file.toURL())
//}
URLClassLoader loader = GroovyObject.class.classLoader
configurations.driver.each {File file ->
loader.addURL(file.toURL())
}
task createDB {
description= "Creates the MariaDB Database. Needs database name to be passed (like: -PdbName=someDBname)"
@@ -37,6 +37,7 @@ import org.springframework.batch.core.annotation.OnSkipInProcess;
import org.springframework.batch.core.annotation.OnSkipInRead;
import org.springframework.batch.core.annotation.OnSkipInWrite;
import org.springframework.batch.core.annotation.OnWriteError;
import org.springframework.batch.item.Chunk;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;
@@ -79,25 +80,25 @@ public abstract class AbstractLoanItemListener {
}
@OnWriteError
public void onWriteError(Exception e, @NotNull List<? extends Loan> items) {
List<Long> loanIds = items.stream().map(AbstractPersistableCustom::getId).toList();
public void onWriteError(Exception e, @NotNull Chunk<? extends Loan> items) {
List<Long> loanIds = items.getItems().stream().map(AbstractPersistableCustom::getId).toList();
log.warn("Error was triggered during writing of Loans (ids={}) due to: {}", loanIds, ThrowableSerialization.serialize(e));
updateAccountLockWithError(loanIds, "Loan (id: %d) writing is failed", e);
}
@OnSkipInRead
public void onSkipInRead(@NotNull Exception e) {
public void onSkipInRead(@NotNull Throwable e) {
log.warn("Skipping was triggered during read!");
}
@OnSkipInProcess
public void onSkipInProcess(@NotNull Loan item, @NotNull Exception e) {
public void onSkipInProcess(@NotNull Loan item, @NotNull Throwable e) {
log.warn("Skipping was triggered during processing of Loan (id={})", item.getId());
}
@OnSkipInWrite
public void onSkipInWrite(@NotNull Loan item, @NotNull Exception e) {
public void onSkipInWrite(@NotNull Loan item, @NotNull Throwable e) {
log.warn("Skipping was triggered during writing of Loan (id={})", item.getId());
}
@@ -22,14 +22,13 @@ import org.apache.fineract.infrastructure.cache.service.RuntimeDelegatingCacheMa
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableCaching
public class PlatformCacheConfiguration extends CachingConfigurerSupport implements CachingConfigurer {
public class PlatformCacheConfiguration implements CachingConfigurer {
@Autowired
private RuntimeDelegatingCacheManager delegatingCacheManager;
@@ -38,7 +38,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.GrantedAuthority;
@@ -57,7 +57,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
@Configuration
@ConditionalOnProperty("fineract.security.oauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity
public class OAuth2SecurityConfig {
@Autowired
@@ -76,9 +76,8 @@ public class OAuth2SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
auth
.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -90,7 +89,14 @@ public class OAuth2SecurityConfig {
.requestMatchers(HttpMethod.POST, "/api/*/twofactor/validate").fullyAuthenticated() //
.requestMatchers("/api/*/twofactor").fullyAuthenticated() //
.requestMatchers("/api/**").access(allOf(fullyAuthenticated(), hasAuthority("TWOFACTOR_AUTHENTICATED"), selfServiceUserAuthManager())); //
}) //
});
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
.exceptionHandling((ehc) -> ehc.authenticationEntryPoint(new OAuth2ExceptionEntryPoint()))
.oauth2ResourceServer(oauth2 -> oauth2.jwt(jwt -> jwt.jwtAuthenticationConverter(authenticationConverter()))
.authenticationEntryPoint(new OAuth2ExceptionEntryPoint())) //
@@ -40,7 +40,7 @@ import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
@@ -53,7 +53,7 @@ import org.springframework.security.web.context.SecurityContextHolderFilter;
@Configuration
@ConditionalOnProperty("fineract.security.basicauth.enabled")
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableMethodSecurity
public class SecurityConfig {
@Autowired
@@ -78,9 +78,8 @@ public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
public SecurityFilterChain authorizationFilterChain(HttpSecurity http) throws Exception {
http //
.csrf((csrf) -> csrf.disable()) // NOSONAR only creating a service that is used by non-browser clients
.securityMatcher("/api/**").authorizeHttpRequests((auth) -> {
auth
.requestMatchers(HttpMethod.OPTIONS, "/api/**").permitAll() //
@@ -94,13 +93,20 @@ 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())); //
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);
.addFilterAfter(loanCOBApiFilter, InsecureTwoFactorAuthenticationFilter.class) //
.addFilterBefore(idempotencyStoreFilter, ExceptionTranslationFilter.class); //
if (serverProperties.getSsl().isEnabled()) {
http.requiresChannel(channel -> channel.requestMatchers("/api/**").requiresSecure());
@@ -20,8 +20,8 @@ package org.apache.fineract.infrastructure.core.diagnostics.performance.sampling
import static java.util.stream.Collectors.toMap;
import java.time.Duration;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.diagnostics.performance.sampling.core.SamplingConfiguration;
@@ -54,8 +54,9 @@ public class SamplingScheduler implements InitializingBean {
log.warn("Reset period for sampling cannot be smaller than 10 seconds, setting back the minimum 10");
resetPeriodInSec = 10;
}
PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSec, TimeUnit.SECONDS);
trigger.setInitialDelay(resetPeriodInSec);
Duration resetPeriodInSecDuration = Duration.ofSeconds(resetPeriodInSec);
PeriodicTrigger trigger = new PeriodicTrigger(resetPeriodInSecDuration);
trigger.setInitialDelay(resetPeriodInSecDuration);
taskScheduler.schedule(this::printAndResetPeriodically, trigger);
}
@@ -36,7 +36,7 @@ import org.springframework.stereotype.Service;
* The {@link RoutingDataSourceService} is responsible for returning the appropriate {@link DataSource} for the tenant
* of this request.
*/
@Service(value = "routingDataSource")
@Service(value = "dataSource")
@Primary
public class RoutingDataSource extends AbstractDataSource {
@@ -25,8 +25,11 @@ import org.apache.fineract.infrastructure.core.service.database.RoutingDataSourc
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.explore.support.JobExplorerFactoryBean;
import org.springframework.batch.core.launch.support.TaskExecutorJobLauncher;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
import org.springframework.batch.core.repository.support.JobRepositoryFactoryBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
@@ -34,7 +37,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
@Configuration(proxyBeanMethods = false)
@EnableBatchProcessing
public class ScheduledJobRunnerConfig {
@@ -49,19 +52,31 @@ public class ScheduledJobRunnerConfig {
}
@Bean
public JobRepositoryFactoryBean jobRepositoryFactoryBean(RoutingDataSource routingDataSource,
PlatformTransactionManager transactionManager) throws Exception {
public Jackson2ExecutionContextStringSerializer executionContextSerializer() {
return new Jackson2ExecutionContextStringSerializer();
}
@Bean
public JobRepository jobRepository(RoutingDataSource routingDataSource,
PlatformTransactionManager transactionManager) throws Exception {
JobRepositoryFactoryBean factory = new JobRepositoryFactoryBean();
factory.setDataSource(routingDataSource);
factory.setTransactionManager(transactionManager);
factory.setIsolationLevelForCreate("ISOLATION_READ_COMMITTED");
factory.setSerializer(executionContextSerializer());
factory.afterPropertiesSet();
return factory;
return factory.getObject();
}
@Bean
public JobRepository jobRepository(JobRepositoryFactoryBean factory) throws Exception {
return factory.getObject();
public JobExplorer jobExplorer(RoutingDataSource routingDataSource,
PlatformTransactionManager transactionManager) throws Exception {
JobExplorerFactoryBean jobExplorerFactoryBean = new JobExplorerFactoryBean();
jobExplorerFactoryBean.setDataSource(routingDataSource);
jobExplorerFactoryBean.setTransactionManager(transactionManager);
jobExplorerFactoryBean.setSerializer(executionContextSerializer());
jobExplorerFactoryBean.afterPropertiesSet();
return jobExplorerFactoryBean.getObject();
}
@Bean
@@ -0,0 +1,32 @@
/**
* 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.jobs.config;
import org.springframework.batch.core.configuration.support.DefaultBatchConfiguration;
import org.springframework.batch.core.repository.ExecutionContextSerializer;
import org.springframework.batch.core.repository.dao.Jackson2ExecutionContextStringSerializer;
//@Configuration(proxyBeanMethods = false)
public class FineractBatchConfiguration extends DefaultBatchConfiguration {
@Override
protected ExecutionContextSerializer getExecutionContextSerializer() {
return new Jackson2ExecutionContextStringSerializer();
}
}
@@ -60,7 +60,7 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
* EntityType = 3 is for loan
*/
@Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan ln WHERE ln.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND ln.loanStatus IN :loanStatuses ")
@Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan loan WHERE loan.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND loan.loanStatus IN :loanStatuses ")
Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId, @Param("loanStatuses") Collection<Integer> loanStatuses);
}
@@ -29,10 +29,10 @@
<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>
@@ -30,6 +30,40 @@
<dropColumn tableName="BATCH_JOB_EXECUTION" columnName="JOB_CONFIGURATION_LOCATION"/>
</changeSet>
<changeSet author="fineract" id="2" context="postgresql">
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = TO_CHAR(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
WHERE TYPE_CD = 'DATE'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = CAST(LONG_VAL AS CHAR)
WHERE TYPE_CD = 'LONG'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = CAST(DOUBLE_VAL AS CHAR)
WHERE TYPE_CD = 'DOUBLE'
</sql>
</changeSet>
<changeSet author="fineract" id="2" context="mysql">
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = DATE_FORMAT(DATE_VAL, 'YYYY-MM-DDTHH:MM:SSZ')
WHERE TYPE_CD = 'DATE'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = LONG_VAL::text
WHERE TYPE_CD = 'LONG'
</sql>
<sql>
UPDATE BATCH_JOB_EXECUTION_PARAMS
SET STRING_VAL = DOUBLE_VAL::text
WHERE TYPE_CD = 'DOUBLE'
</sql>
</changeSet>
<changeSet author="fineract" id="4" context="postgresql">
<!--
org/springframework/batch/core/migration/5.0/migration-postgresql.sql
-->
@@ -58,7 +92,7 @@
</sql>
</changeSet>
<changeSet author="fineract" id="3" context="mysql">
<changeSet author="fineract" id="4" context="mysql">
<!--
org/springframework/batch/core/migration/5.0/migration-mysql.sql
-->
@@ -75,4 +109,22 @@
ALTER TABLE BATCH_JOB_EXECUTION_PARAMS CHANGE COLUMN STRING_VAL PARAMETER_VALUE VARCHAR(2500);
</sql>
</changeSet>
<changeSet author="fineract" id="5">
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.Long"/>
<where>PARAMETER_TYPE='LONG'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.String"/>
<where>PARAMETER_TYPE='STRING'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.lang.Double"/>
<where>PARAMETER_TYPE='DOUBLE'</where>
</update>
<update tableName="BATCH_JOB_EXECUTION_PARAMS">
<column name="PARAMETER_TYPE" value="java.util.Date"/>
<where>PARAMETER_TYPE='DATE'</where>
</update>
</changeSet>
</databaseChangeLog>
@@ -38,6 +38,7 @@ import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.mockito.Mockito;
import org.springframework.batch.item.Chunk;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.support.TransactionTemplate;
@@ -107,7 +108,7 @@ public class LoanItemListenerStepDefinitions implements En {
});
When("LoanItemListener.onWriteError method executed", () -> {
loanItemListener.onWriteError(exception, List.of(loan));
loanItemListener.onWriteError(exception, new Chunk<>(List.of(loan)));
});
Then("LoanItemListener.onWriteError result should match", () -> {