diff --git a/app/server/appsmith-interfaces/pom.xml b/app/server/appsmith-interfaces/pom.xml index 17b89cc2d0..83d43f4e56 100644 --- a/app/server/appsmith-interfaces/pom.xml +++ b/app/server/appsmith-interfaces/pom.xml @@ -86,6 +86,11 @@ compile + + org.springframework.security + spring-security-crypto + + org.projectlombok lombok diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/annotations/encryption/EncryptionMongoEventListener.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/annotations/encryption/EncryptionMongoEventListener.java index 7e687582e9..a82397b943 100644 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/annotations/encryption/EncryptionMongoEventListener.java +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/annotations/encryption/EncryptionMongoEventListener.java @@ -1,6 +1,6 @@ package com.appsmith.external.annotations.encryption; -import com.appsmith.external.services.EncryptionService; +import com.appsmith.external.helpers.EncryptionHelper; import lombok.extern.slf4j.Slf4j; import org.springframework.data.mongodb.core.mapping.event.AbstractMongoEventListener; import org.springframework.data.mongodb.core.mapping.event.AfterConvertEvent; @@ -9,13 +9,7 @@ import org.springframework.data.mongodb.core.mapping.event.BeforeConvertEvent; @Slf4j public class EncryptionMongoEventListener extends AbstractMongoEventListener { - private final EncryptionService encryptionService; - EncryptionHandler encryptionHandler; - - public EncryptionMongoEventListener(EncryptionService encryptionService) { - encryptionHandler = new EncryptionHandler(); - this.encryptionService = encryptionService; - } + private final EncryptionHandler encryptionHandler = new EncryptionHandler(); // This lifecycle event is before we save a document into the DB, // and even before the mapper has converted the object into a document type @@ -23,7 +17,7 @@ public class EncryptionMongoEventListener extends AbstractMongoEventListener< public void onBeforeConvert(BeforeConvertEvent event) { E source = event.getSource(); - encryptionHandler.convertEncryption(source, encryptionService::encryptString); + encryptionHandler.convertEncryption(source, EncryptionHelper::encrypt); } // This lifecycle event is after we retrieve a document from the DB, @@ -32,6 +26,6 @@ public class EncryptionMongoEventListener extends AbstractMongoEventListener< public void onAfterConvert(AfterConvertEvent event) { E source = event.getSource(); - encryptionHandler.convertEncryption(source, encryptionService::decryptString); + encryptionHandler.convertEncryption(source, EncryptionHelper::decrypt); } } diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/EncryptionHelper.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/EncryptionHelper.java new file mode 100644 index 0000000000..2db97a9f4e --- /dev/null +++ b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/EncryptionHelper.java @@ -0,0 +1,41 @@ +package com.appsmith.external.helpers; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.security.crypto.encrypt.Encryptors; +import org.springframework.security.crypto.encrypt.TextEncryptor; + +import java.util.HexFormat; + +public final class EncryptionHelper { + + private static final String salt = requireEnv("APPSMITH_ENCRYPTION_SALT"); + + private static final String password = requireEnv("APPSMITH_ENCRYPTION_PASSWORD"); + + private static final HexFormat hexFormat = HexFormat.of(); + + private static final TextEncryptor textEncryptor = makeTextEncryptor(); + + private EncryptionHelper() {} + + private static TextEncryptor makeTextEncryptor() { + final String saltInHex = hexFormat.formatHex(salt.getBytes()); + return Encryptors.delux(password, saltInHex); + } + + public static String encrypt(String plaintext) { + return textEncryptor.encrypt(plaintext); + } + + public static String decrypt(String encryptedText) { + return textEncryptor.decrypt(encryptedText); + } + + private static String requireEnv(String name) { + final String value = System.getenv(name); + if (StringUtils.isBlank(value)) { + throw new RuntimeException("Environment variable '%s' is required".formatted(name)); + } + return value; + } +} diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/EncryptionService.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/EncryptionService.java deleted file mode 100644 index 4abb39291b..0000000000 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/EncryptionService.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.appsmith.external.services; - -import com.appsmith.external.services.ce.EncryptionServiceCE; - -public interface EncryptionService extends EncryptionServiceCE {} diff --git a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/ce/EncryptionServiceCE.java b/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/ce/EncryptionServiceCE.java deleted file mode 100644 index 6a7fa0f1e6..0000000000 --- a/app/server/appsmith-interfaces/src/main/java/com/appsmith/external/services/ce/EncryptionServiceCE.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.appsmith.external.services.ce; - -public interface EncryptionServiceCE { - - String encryptString(String plaintext); - - String decryptString(String encryptedText); -} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/EncryptionConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/EncryptionConfig.java deleted file mode 100644 index 79be92c48c..0000000000 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/EncryptionConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.appsmith.server.configurations; - -import lombok.Getter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; - -@Configuration -@Getter -public class EncryptionConfig { - - @Value("${encrypt.salt}") - private String salt; - - @Value("${encrypt.password}") - private String password; -} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/MongoConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/MongoConfig.java index 29a7b7834a..6cbf63c2b7 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/MongoConfig.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/MongoConfig.java @@ -3,7 +3,6 @@ package com.appsmith.server.configurations; import com.appsmith.external.annotations.documenttype.DocumentTypeMapper; import com.appsmith.external.annotations.encryption.EncryptionMongoEventListener; import com.appsmith.external.models.AuthenticationDTO; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.configurations.mongo.SoftDeleteMongoRepositoryFactoryBean; import com.appsmith.server.converters.StringToInstantConverter; import com.appsmith.server.repositories.BaseRepositoryImpl; @@ -266,8 +265,8 @@ public class MongoConfig { } @Bean - public EncryptionMongoEventListener encryptionMongoEventListener(EncryptionService encryptionService) { - return new EncryptionMongoEventListener(encryptionService); + public EncryptionMongoEventListener encryptionMongoEventListener() { + return new EncryptionMongoEventListener(); } @Bean diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/EncryptionServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/EncryptionServiceImpl.java deleted file mode 100644 index 5f4548bfe2..0000000000 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/EncryptionServiceImpl.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.appsmith.server.services; - -import com.appsmith.external.services.EncryptionService; -import com.appsmith.server.configurations.EncryptionConfig; -import com.appsmith.server.services.ce.EncryptionServiceCEImpl; -import org.springframework.stereotype.Service; - -@Service -public class EncryptionServiceImpl extends EncryptionServiceCEImpl implements EncryptionService { - - public EncryptionServiceImpl(EncryptionConfig encryptionConfig) { - super(encryptionConfig); - } -} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java index f07cafeab4..bed86dbc47 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/UserServiceImpl.java @@ -1,6 +1,5 @@ package com.appsmith.server.services; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.configurations.CommonConfig; import com.appsmith.server.configurations.EmailConfig; import com.appsmith.server.helpers.UserServiceHelper; @@ -35,7 +34,6 @@ public class UserServiceImpl extends UserServiceCECompatibleImpl implements User PolicySolution policySolution, CommonConfig commonConfig, EmailConfig emailConfig, - EncryptionService encryptionService, UserDataService userDataService, TenantService tenantService, PermissionGroupService permissionGroupService, @@ -54,7 +52,6 @@ public class UserServiceImpl extends UserServiceCECompatibleImpl implements User passwordResetTokenRepository, passwordEncoder, commonConfig, - encryptionService, userDataService, tenantService, userUtils, diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/EncryptionServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/EncryptionServiceCEImpl.java deleted file mode 100644 index 0f7d61c5cd..0000000000 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/EncryptionServiceCEImpl.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.appsmith.server.services.ce; - -import com.appsmith.external.services.ce.EncryptionServiceCE; -import com.appsmith.server.configurations.EncryptionConfig; -import org.apache.commons.codec.binary.Hex; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.security.crypto.encrypt.Encryptors; -import org.springframework.security.crypto.encrypt.TextEncryptor; - -public class EncryptionServiceCEImpl implements EncryptionServiceCE { - - private final EncryptionConfig encryptionConfig; - - private TextEncryptor textEncryptor; - - @Autowired - public EncryptionServiceCEImpl(EncryptionConfig encryptionConfig) { - this.encryptionConfig = encryptionConfig; - String saltInHex = Hex.encodeHexString(encryptionConfig.getSalt().getBytes()); - this.textEncryptor = Encryptors.delux(encryptionConfig.getPassword(), saltInHex); - } - - @Override - public String encryptString(String plaintext) { - return textEncryptor.encrypt(plaintext); - } - - @Override - public String decryptString(String encryptedText) { - return textEncryptor.decrypt(encryptedText); - } -} diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java index afddfb2337..ca6cb2f604 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/UserServiceCEImpl.java @@ -1,7 +1,7 @@ package com.appsmith.server.services.ce; import com.appsmith.external.helpers.AppsmithBeanUtils; -import com.appsmith.external.services.EncryptionService; +import com.appsmith.external.helpers.EncryptionHelper; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.configurations.CommonConfig; import com.appsmith.server.constants.FieldName; @@ -96,7 +96,6 @@ public class UserServiceCEImpl extends BaseService private final PasswordEncoder passwordEncoder; private final CommonConfig commonConfig; - private final EncryptionService encryptionService; private final UserDataService userDataService; private final TenantService tenantService; private final UserUtils userUtils; @@ -128,7 +127,6 @@ public class UserServiceCEImpl extends BaseService PasswordResetTokenRepository passwordResetTokenRepository, PasswordEncoder passwordEncoder, CommonConfig commonConfig, - EncryptionService encryptionService, UserDataService userDataService, TenantService tenantService, UserUtils userUtils, @@ -144,7 +142,6 @@ public class UserServiceCEImpl extends BaseService this.passwordResetTokenRepository = passwordResetTokenRepository; this.passwordEncoder = passwordEncoder; this.commonConfig = commonConfig; - this.encryptionService = encryptionService; this.userDataService = userDataService; this.tenantService = tenantService; this.userUtils = userUtils; @@ -225,7 +222,7 @@ public class UserServiceCEImpl extends BaseService String resetUrl = String.format( FORGOT_PASSWORD_CLIENT_URL_FORMAT, resetUserPasswordDTO.getBaseUrl(), - encryptionService.encryptString(urlParams)); + EncryptionHelper.encrypt(urlParams)); log.debug("Password reset url for email: {}: {}", passwordResetToken.getEmail(), resetUrl); @@ -695,7 +692,7 @@ public class UserServiceCEImpl extends BaseService } private EmailTokenDTO parseValueFromEncryptedToken(String encryptedToken) { - String decryptString = encryptionService.decryptString(encryptedToken); + String decryptString = EncryptionHelper.decrypt(encryptedToken); List nameValuePairs = WWWFormCodec.parse(decryptString, StandardCharsets.UTF_8); Map params = new HashMap<>(); @@ -780,7 +777,7 @@ public class UserServiceCEImpl extends BaseService String verificationUrl = String.format( EMAIL_VERIFICATION_CLIENT_URL_FORMAT, resendEmailVerificationDTO.getBaseUrl(), - encryptionService.encryptString(urlParams), + EncryptionHelper.encrypt(urlParams), URLEncoder.encode(emailVerificationToken.getEmail(), StandardCharsets.UTF_8), redirectUrlCopy); diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce_compatible/UserServiceCECompatibleImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce_compatible/UserServiceCECompatibleImpl.java index 112ab57273..7589ceac4a 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce_compatible/UserServiceCECompatibleImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce_compatible/UserServiceCECompatibleImpl.java @@ -1,6 +1,5 @@ package com.appsmith.server.services.ce_compatible; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.configurations.CommonConfig; import com.appsmith.server.helpers.UserServiceHelper; import com.appsmith.server.helpers.UserUtils; @@ -31,7 +30,6 @@ public class UserServiceCECompatibleImpl extends UserServiceCEImpl implements Us PasswordResetTokenRepository passwordResetTokenRepository, PasswordEncoder passwordEncoder, CommonConfig commonConfig, - EncryptionService encryptionService, UserDataService userDataService, TenantService tenantService, UserUtils userUtils, @@ -49,7 +47,6 @@ public class UserServiceCECompatibleImpl extends UserServiceCEImpl implements Us passwordResetTokenRepository, passwordEncoder, commonConfig, - encryptionService, userDataService, tenantService, userUtils, diff --git a/app/server/appsmith-server/src/main/resources/application.properties b/app/server/appsmith-server/src/main/resources/application.properties index fcd07b99ea..58281832ee 100644 --- a/app/server/appsmith-server/src/main/resources/application.properties +++ b/app/server/appsmith-server/src/main/resources/application.properties @@ -87,11 +87,6 @@ appsmith.cloud_services.signature_base_url = ${APPSMITH_CLOUD_SERVICES_SIGNATURE appsmith.cloud_services.template_upload_auth_header = ${APPSMITH_CLOUD_SERVICES_TEMPLATE_UPLOAD_AUTH:} github_repo = ${APPSMITH_GITHUB_REPO:} -# MANDATORY!! No default properties are being provided for encryption password and salt for security. -# The server would not come up without these values provided through the environment variables. -encrypt.password=${APPSMITH_ENCRYPTION_PASSWORD:} -encrypt.salt=${APPSMITH_ENCRYPTION_SALT:} - # The following configurations are to help support prometheus scraping for monitoring management.endpoints.web.exposure.include=prometheus,metrics management.tracing.enabled=${APPSMITH_TRACING_ENABLED:false} diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java index d813c3da15..d0cc18c2d2 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceContextServiceTest.java @@ -1,6 +1,7 @@ package com.appsmith.server.services; import com.appsmith.external.constants.PluginConstants; +import com.appsmith.external.helpers.EncryptionHelper; import com.appsmith.external.helpers.restApiUtils.connections.APIConnection; import com.appsmith.external.helpers.restApiUtils.connections.APIConnectionFactory; import com.appsmith.external.helpers.restApiUtils.connections.BearerTokenAuthentication; @@ -17,7 +18,6 @@ import com.appsmith.external.models.DatasourceStorageDTO; import com.appsmith.external.models.OAuth2; import com.appsmith.external.models.UpdatableConnection; import com.appsmith.external.plugins.PluginExecutor; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.datasources.base.DatasourceService; import com.appsmith.server.datasourcestorages.base.DatasourceStorageService; @@ -73,9 +73,6 @@ import static org.mockito.Mockito.spy; @Slf4j public class DatasourceContextServiceTest { - @Autowired - EncryptionService encryptionService; - @Autowired WorkspaceRepository workspaceRepository; @@ -287,7 +284,7 @@ public class DatasourceContextServiceTest { DBAuth encryptedAuthentication = (DBAuth) savedDatasourceStorageDTO .getDatasourceConfiguration() .getAuthentication(); - assertEquals(password, encryptionService.decryptString(encryptedAuthentication.getPassword())); + assertEquals(password, EncryptionHelper.decrypt(encryptedAuthentication.getPassword())); }) .verifyComplete(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java index 5744932c5d..c23d8aa2fb 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/DatasourceServiceTest.java @@ -1,5 +1,6 @@ package com.appsmith.server.services; +import com.appsmith.external.helpers.EncryptionHelper; import com.appsmith.external.models.ActionConfiguration; import com.appsmith.external.models.ActionDTO; import com.appsmith.external.models.Connection; @@ -14,7 +15,6 @@ import com.appsmith.external.models.OAuth2; import com.appsmith.external.models.Policy; import com.appsmith.external.models.SSLDetails; import com.appsmith.external.models.UploadedFile; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.acl.AclPermission; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.constants.FieldName; @@ -103,9 +103,6 @@ public class DatasourceServiceTest { @Autowired ApplicationPageService applicationPageService; - @Autowired - EncryptionService encryptionService; - @Autowired LayoutActionService layoutActionService; @@ -1095,7 +1092,7 @@ public class DatasourceServiceTest { DBAuth authentication = (DBAuth) datasourceStorageDTO.getDatasourceConfiguration().getAuthentication(); assertThat(authentication.getUsername()).isEqualTo(username); - assertThat(encryptionService.decryptString(authentication.getPassword())) + assertThat(EncryptionHelper.decrypt(authentication.getPassword())) .isEqualTo(password); }) .verifyComplete(); @@ -1226,7 +1223,7 @@ public class DatasourceServiceTest { datasourceStorageDTO.getDatasourceConfiguration().getAuthentication(); assertThat(authentication.getUsername()).isEqualTo(username); - assertThat(password).isEqualTo(encryptionService.decryptString(authentication.getPassword())); + assertThat(password).isEqualTo(EncryptionHelper.decrypt(authentication.getPassword())); }) .verifyComplete(); } diff --git a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserServiceTest.java b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserServiceTest.java index 0478ddb852..bde3812eae 100644 --- a/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserServiceTest.java +++ b/app/server/appsmith-server/src/test/java/com/appsmith/server/services/UserServiceTest.java @@ -1,7 +1,7 @@ package com.appsmith.server.services; +import com.appsmith.external.helpers.EncryptionHelper; import com.appsmith.external.models.Policy; -import com.appsmith.external.services.EncryptionService; import com.appsmith.server.applications.base.ApplicationService; import com.appsmith.server.configurations.CommonConfig; import com.appsmith.server.configurations.WithMockAppsmithUser; @@ -92,9 +92,6 @@ public class UserServiceTest { @Autowired PasswordEncoder passwordEncoder; - @Autowired - EncryptionService encryptionService; - @Autowired UserDataService userDataService; @@ -552,7 +549,7 @@ public class UserServiceTest { nameValuePairs.add(new BasicNameValuePair("email", emailAddress)); nameValuePairs.add(new BasicNameValuePair("token", token)); String urlParams = WWWFormCodec.format(nameValuePairs, StandardCharsets.UTF_8); - return encryptionService.encryptString(urlParams); + return EncryptionHelper.encrypt(urlParams); } @Test