chore: Make core encrypt/decrypt methods statically available (#34117)
Two goals. 1. Move encryption/decryption implementation to `interfaces` module. Today, only the interfaces are in `interfaces` module, not the implementations. We need the implementation also to be in `interfaces`. We need this for solving encryption/decryption in the `pg` branch. 2. Make the encryption and decryption functions be static, and not depend on Spring's DI system. We need this to be available _before_ Spring's DI kicks in, during runtime annotation processing by Hibernate, so we need it to be just static functions, and not depend on Spring havin initialized. This also means that we have to read the env variables directly. The `application.properties` is loaded by Spring, and since we want this information before Spring intializes, we'll need to read the env variables directly. ⚠️ There's conflicts and additional changes needed on EE for build to pass. **DO NOT MERGE** unless the author is known to be available. EE PR also passed all at https://github.com/appsmithorg/appsmith-ee/pull/4282. **/test all** <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/9467180088> > Commit: 402785da8df5aa6b4eeec9955421ce1ff7af305f > Cypress dashboard url: <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=9467180088&attempt=1" target="_blank">Click here!</a> <!-- end of auto-generated comment: Cypress test results -->
This commit is contained in:
parent
3749688eb5
commit
be76aeed60
|
|
@ -86,6 +86,11 @@
|
|||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-crypto</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
|
|
|||
|
|
@ -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<E> extends AbstractMongoEventListener<E> {
|
||||
|
||||
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<E> extends AbstractMongoEventListener<
|
|||
public void onBeforeConvert(BeforeConvertEvent<E> 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<E> extends AbstractMongoEventListener<
|
|||
public void onAfterConvert(AfterConvertEvent<E> event) {
|
||||
E source = event.getSource();
|
||||
|
||||
encryptionHandler.convertEncryption(source, encryptionService::decryptString);
|
||||
encryptionHandler.convertEncryption(source, EncryptionHelper::decrypt);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
41
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/EncryptionHelper.java
vendored
Normal file
41
app/server/appsmith-interfaces/src/main/java/com/appsmith/external/helpers/EncryptionHelper.java
vendored
Normal file
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
package com.appsmith.external.services;
|
||||
|
||||
import com.appsmith.external.services.ce.EncryptionServiceCE;
|
||||
|
||||
public interface EncryptionService extends EncryptionServiceCE {}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
package com.appsmith.external.services.ce;
|
||||
|
||||
public interface EncryptionServiceCE {
|
||||
|
||||
String encryptString(String plaintext);
|
||||
|
||||
String decryptString(String encryptedText);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UserRepository, User, String>
|
|||
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<UserRepository, User, String>
|
|||
PasswordResetTokenRepository passwordResetTokenRepository,
|
||||
PasswordEncoder passwordEncoder,
|
||||
CommonConfig commonConfig,
|
||||
EncryptionService encryptionService,
|
||||
UserDataService userDataService,
|
||||
TenantService tenantService,
|
||||
UserUtils userUtils,
|
||||
|
|
@ -144,7 +142,6 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
|||
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<UserRepository, User, String>
|
|||
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<UserRepository, User, String>
|
|||
}
|
||||
|
||||
private EmailTokenDTO parseValueFromEncryptedToken(String encryptedToken) {
|
||||
String decryptString = encryptionService.decryptString(encryptedToken);
|
||||
String decryptString = EncryptionHelper.decrypt(encryptedToken);
|
||||
List<NameValuePair> nameValuePairs = WWWFormCodec.parse(decryptString, StandardCharsets.UTF_8);
|
||||
Map<String, String> params = new HashMap<>();
|
||||
|
||||
|
|
@ -780,7 +777,7 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
|||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user