From 11e72d6a9acd94f6dead31a6dcd77e0132c546f7 Mon Sep 17 00:00:00 2001 From: Pareekshith1 Date: Sun, 29 Jun 2025 20:45:52 +0530 Subject: [PATCH 1/3] Implemented Decryption --- .gitignore | 1 + build.gradle | 1 + fineract-provider/build.gradle | 2 + .../api/AuthenticationApiResource.java | 39 ++++++++++++++++++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 10983c86887..f024f4f6ebe 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ .project .settings .gradle +.env build .env *.iml diff --git a/build.gradle b/build.gradle index 1e36d780862..6da1e2eb454 100644 --- a/build.gradle +++ b/build.gradle @@ -667,6 +667,7 @@ configure(project.fineractCustomProjects) { implementation ("ch.qos.logback:logback-classic") { exclude(module: "slf4j-api") } + implementation 'io.github.cdimascio:java-dotenv:5.2.2' compileOnly('org.projectlombok:lombok') annotationProcessor('org.projectlombok:lombok') diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index 118620ec8d0..013a528a556 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -225,6 +225,8 @@ bootRun { dependencies { implementation 'org.mariadb.jdbc:mariadb-java-client' implementation 'org.postgresql:postgresql' + implementation 'io.github.cdimascio:java-dotenv:5.2.2' + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java index d0dc6130237..4ac7bdcc4a6 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java @@ -39,6 +39,10 @@ import java.util.Base64; import java.util.Collection; import java.util.Set; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; +import javax.crypto.Cipher; import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.core.data.EnumOptionData; import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; @@ -57,6 +61,7 @@ import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; +import io.github.cdimascio.dotenv.Dotenv; @Component @ConditionalOnProperty("fineract.security.basicauth.enabled") @@ -67,6 +72,7 @@ public class AuthenticationApiResource { @Value("${fineract.security.2fa.enabled}") private boolean twoFactorEnabled; + private static final Dotenv dotenv = Dotenv.load(); public static class AuthenticateRequest { @@ -101,6 +107,13 @@ public String authenticate(@Parameter(hidden = true) final String apiRequestBody throw new IllegalArgumentException("Username or Password is null in JSON (see FINERACT-726) of POST to /authentication: " + apiRequestBodyAsJson + "; username=" + request.username + ", password=" + request.password); } + + // decryption logic tries and catches method + try { + request.password = decryptPassword(request.password); + } catch (Exception e) { + throw new IllegalArgumentException("Password decryption failed: " + e.getMessage(), e); + } AppUser appUser = this.springSecurityPlatformSecurityContext.getAppUserByUsername(request.username); @@ -130,7 +143,7 @@ public String authenticate(@Parameter(hidden = true) final String apiRequestBody principal.setFailedLoginAttempts(0); principal.setCredentialsNonExpired(true); this.springSecurityPlatformSecurityContext.saveAppUser(principal); - + final Collection permissions = new ArrayList<>(); AuthenticatedUserData authenticatedUserData = new AuthenticatedUserData().setUsername(request.username).setPermissions(permissions); @@ -182,4 +195,28 @@ public String authenticate(@Parameter(hidden = true) final String apiRequestBody return this.apiJsonSerializerService.serialize(authenticatedUserData); } + + // The password decryption method + private String decryptPassword(String encryptedPassword) throws Exception { + String privateKeyPEM = dotenv.get("FINERACT_RSA_PRIVATE_KEY"); + if (privateKeyPEM == null) { + throw new IllegalStateException("Server private key not configured in FINERACT_RSA_PRIVATE_KEY"); + } + + privateKeyPEM = privateKeyPEM + .replace("-----BEGIN PRIVATE KEY-----", "") + .replace("-----END PRIVATE KEY-----", "") + .replaceAll("\\s+", ""); + + byte[] keyBytes = Base64.getDecoder().decode(privateKeyPEM); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + PrivateKey privateKey = keyFactory.generatePrivate(keySpec); + + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, privateKey); + + byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedPassword)); + return new String(decryptedBytes, StandardCharsets.UTF_8); + } } From f553d091d4e402b502d8b9ac6ba4535dc53bf52a Mon Sep 17 00:00:00 2001 From: Pareekshith1 Date: Wed, 2 Jul 2025 10:56:47 +0530 Subject: [PATCH 2/3] Fix: Updated build.gradle after rebase --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 6da1e2eb454..23216de51eb 100644 --- a/build.gradle +++ b/build.gradle @@ -667,7 +667,7 @@ configure(project.fineractCustomProjects) { implementation ("ch.qos.logback:logback-classic") { exclude(module: "slf4j-api") } - implementation 'io.github.cdimascio:java-dotenv:5.2.2' + compileOnly('org.projectlombok:lombok') annotationProcessor('org.projectlombok:lombok') From a46b69eec06293d8b9f2118d4ff32e7257a0a595 Mon Sep 17 00:00:00 2001 From: Pareekshith1 Date: Wed, 2 Jul 2025 10:58:49 +0530 Subject: [PATCH 3/3] Fix: Updated build.gradle after rebase and space resolvement --- build.gradle | 1 - fineract-provider/build.gradle | 1 - .../infrastructure/security/api/AuthenticationApiResource.java | 2 -- 3 files changed, 4 deletions(-) diff --git a/build.gradle b/build.gradle index 23216de51eb..1e36d780862 100644 --- a/build.gradle +++ b/build.gradle @@ -668,7 +668,6 @@ configure(project.fineractCustomProjects) { exclude(module: "slf4j-api") } - compileOnly('org.projectlombok:lombok') annotationProcessor('org.projectlombok:lombok') annotationProcessor('org.mapstruct:mapstruct-processor') diff --git a/fineract-provider/build.gradle b/fineract-provider/build.gradle index 013a528a556..0b8d7379f03 100644 --- a/fineract-provider/build.gradle +++ b/fineract-provider/build.gradle @@ -226,7 +226,6 @@ bootRun { implementation 'org.mariadb.jdbc:mariadb-java-client' implementation 'org.postgresql:postgresql' implementation 'io.github.cdimascio:java-dotenv:5.2.2' - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java index 4ac7bdcc4a6..cf72557a833 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/security/api/AuthenticationApiResource.java @@ -107,7 +107,6 @@ public String authenticate(@Parameter(hidden = true) final String apiRequestBody throw new IllegalArgumentException("Username or Password is null in JSON (see FINERACT-726) of POST to /authentication: " + apiRequestBodyAsJson + "; username=" + request.username + ", password=" + request.password); } - // decryption logic tries and catches method try { request.password = decryptPassword(request.password); @@ -195,7 +194,6 @@ public String authenticate(@Parameter(hidden = true) final String apiRequestBody return this.apiJsonSerializerService.serialize(authenticatedUserData); } - // The password decryption method private String decryptPassword(String encryptedPassword) throws Exception { String privateKeyPEM = dotenv.get("FINERACT_RSA_PRIVATE_KEY");