galovics commented on code in PR #3011: URL: https://github.com/apache/fineract/pull/3011#discussion_r1122297080
########## fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DatabasePasswordEncryptor.java: ########## @@ -0,0 +1,73 @@ +/** + * 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.service.database; + +import java.nio.charset.StandardCharsets; +import java.util.Optional; +import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.core.config.FineractProperties; +import org.apache.fineract.infrastructure.security.service.PasswordEncryptor; +import org.apache.fineract.infrastructure.security.utils.EncryptionUtil; +import org.springframework.security.crypto.bcrypt.BCrypt; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DatabasePasswordEncryptor implements PasswordEncryptor { + + public static final String DEFAULT_ENCRYPTION = "AES/CBC/PKCS5Padding"; + + public static final String DEFAULT_MASTER_PASSWORD = "fineract"; + + private final FineractProperties fineractProperties; + + @Override + public String encrypt(String plainPassword) { + String masterPassword = Optional.ofNullable(fineractProperties.getTenant()) + .map(FineractProperties.FineractTenantProperties::getMasterPassword).orElse(DEFAULT_MASTER_PASSWORD); + String encryption = Optional.ofNullable(fineractProperties.getTenant()) + .map(FineractProperties.FineractTenantProperties::getEncryption).orElse(DEFAULT_ENCRYPTION); + return EncryptionUtil.encryptToBase64(encryption, masterPassword, plainPassword); + } + + @Override + public String decrypt(String encryptedPassword) { + String masterPassword = Optional.ofNullable(fineractProperties.getTenant()) + .map(FineractProperties.FineractTenantProperties::getMasterPassword).orElse(DEFAULT_MASTER_PASSWORD); + String encryption = Optional.ofNullable(fineractProperties.getTenant()) + .map(FineractProperties.FineractTenantProperties::getEncryption).orElse(DEFAULT_ENCRYPTION); + return EncryptionUtil.decryptFromBase64(encryption, masterPassword, encryptedPassword); + } + + public String getMasterPasswordHash() { + String masterPassword = Optional.ofNullable(fineractProperties) // + .map(FineractProperties::getTenant) // + .map(FineractProperties.FineractTenantProperties::getMasterPassword) // + .orElse(DEFAULT_MASTER_PASSWORD); + return BCrypt.hashpw(masterPassword.getBytes(StandardCharsets.UTF_8), BCrypt.gensalt()); + } + + public boolean isPasswordValid(String hashed) { Review Comment: I'd call this isMasterPasswordHashValid ########## fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/database/DataSourcePerTenantServiceFactory.java: ########## @@ -47,16 +47,23 @@ public class DataSourcePerTenantServiceFactory { private final DataSource tenantDataSource; private final HikariDataSourceFactory hikariDataSourceFactory; + private final DatabasePasswordEncryptor databasePasswordEncryptor; + public DataSourcePerTenantServiceFactory(@Qualifier("hikariTenantDataSource") DataSource tenantDataSource, HikariConfig hikariConfig, - FineractProperties fineractProperties, ApplicationContext context, HikariDataSourceFactory hikariDataSourceFactory) { + FineractProperties fineractProperties, ApplicationContext context, HikariDataSourceFactory hikariDataSourceFactory, + DatabasePasswordEncryptor databasePasswordEncryptor) { this.hikariConfig = hikariConfig; this.fineractProperties = fineractProperties; this.context = context; this.tenantDataSource = tenantDataSource; this.hikariDataSourceFactory = hikariDataSourceFactory; + this.databasePasswordEncryptor = databasePasswordEncryptor; } public DataSource createNewDataSourceFor(final FineractPlatformTenantConnection tenantConnection) { + if (!databasePasswordEncryptor.isPasswordValid(tenantConnection.getMasterPasswordHash())) { + throw new IllegalArgumentException("Invalid master password"); Review Comment: Can we include the tenant ID in the message? If somebody encounters this error, they won't know which tenant has the wrong password. ########## fineract-provider/src/main/java/org/apache/fineract/infrastructure/core/service/migration/TenantDatabaseUpgradeService.java: ########## @@ -59,6 +60,8 @@ public class TenantDatabaseUpgradeService implements InitializingBean { private final TenantDataSourceFactory tenantDataSourceFactory; private final Environment environment; + private final List<CustomTaskChange> customTaskChangesForDependencyInjection; Review Comment: Is this needed to ensure the ordering of bean creation? If so, can you make a comment here on that so nobody will delete it? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
