chore: Removing user repo fetches only by email (#40165)
## Description > [!TIP] > _Add a TL;DR when the description is longer than 500 words or extremely technical (helps the content, marketing, and DevRel team)._ > > _Please also include relevant motivation and context. List any dependencies that are required for this change. Add links to Notion, Figma or any other documents that might be relevant to the PR._ Fixes #`Issue Number` _or_ Fixes `Issue URL` > [!WARNING] > _If no issue exists, please create an issue first, and check with the maintainers if the issue is valid._ ## Automation /test sanity ### 🔍 Cypress test results <!-- This is an auto-generated comment: Cypress test results --> > [!TIP] > 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉 > Workflow run: <https://github.com/appsmithorg/appsmith/actions/runs/14330369135> > Commit: ea2dba000d77e0b8cd7a46ba2259a076bfb4086e > <a href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=14330369135&attempt=1" target="_blank">Cypress dashboard</a>. > Tags: `@tag.Sanity` > Spec: > <hr>Tue, 08 Apr 2025 10:21:54 UTC <!-- end of auto-generated comment: Cypress test results --> ## Communication Should the DevRel and Marketing teams inform users about this change? - [ ] Yes - [ ] No <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **Refactor** - Streamlined user account and session management workflows by integrating organization-specific checks into processes like password resets, invitations, and general user retrieval. - Phased out older lookup methods in favor of a more robust, organization-aware approach that enhances both accuracy and security. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
parent
507bb90307
commit
933e968d34
|
|
@ -11,6 +11,7 @@ import java.util.Set;
|
|||
|
||||
public interface UserRepositoryCE extends BaseRepository<User, String>, CustomUserRepository {
|
||||
|
||||
@Deprecated
|
||||
Mono<User> findByEmail(String email);
|
||||
|
||||
Mono<User> findFirstByEmailIgnoreCaseAndOrganizationIdOrderByCreatedAtDesc(String email, String organizationId);
|
||||
|
|
|
|||
|
|
@ -44,7 +44,9 @@ public class SessionUserServiceCEImpl implements SessionUserServiceCE {
|
|||
@Override
|
||||
public Mono<User> refreshCurrentUser(ServerWebExchange exchange) {
|
||||
return Mono.zip(
|
||||
getCurrentUser().map(User::getEmail).flatMap(userRepository::findByEmail),
|
||||
getCurrentUser()
|
||||
.flatMap(sessionUser -> userRepository.findByEmailAndOrganizationId(
|
||||
sessionUser.getEmail(), sessionUser.getOrganizationId())),
|
||||
ReactiveSecurityContextHolder.getContext(),
|
||||
exchange.getSession())
|
||||
.flatMap(tuple -> {
|
||||
|
|
|
|||
|
|
@ -324,6 +324,8 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
|||
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, USER, ORGANIZATION)))
|
||||
.cache();
|
||||
|
||||
Mono<String> orgIdMono = organizationMono.map(Organization::getId);
|
||||
|
||||
return organizationMono
|
||||
.flatMap(organization -> passwordResetTokenRepository.findByEmailAndOrganizationId(
|
||||
emailTokenDTO.getEmail(), organization.getId()))
|
||||
|
|
@ -337,69 +339,69 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
|||
return emailTokenDTO.getEmail();
|
||||
}
|
||||
})
|
||||
.flatMap(emailAddress -> repository
|
||||
.findByEmail(emailAddress)
|
||||
.switchIfEmpty(Mono.error(
|
||||
new AppsmithException(AppsmithError.NO_RESOURCE_FOUND, FieldName.USER, emailAddress)))
|
||||
.zipWith(organizationMono)
|
||||
.flatMap(tuple -> {
|
||||
User userFromDb = tuple.getT1();
|
||||
OrganizationConfiguration organizationConfiguration =
|
||||
tuple.getT2().getOrganizationConfiguration();
|
||||
boolean isStrongPasswordPolicyEnabled = organizationConfiguration != null
|
||||
&& Boolean.TRUE.equals(
|
||||
organizationConfiguration.getIsStrongPasswordPolicyEnabled());
|
||||
.zipWith(orgIdMono)
|
||||
.flatMap(tuple -> {
|
||||
String emailAddress = tuple.getT1();
|
||||
String orgId = tuple.getT2();
|
||||
return repository
|
||||
.findByEmailAndOrganizationId(emailAddress, orgId)
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(
|
||||
AppsmithError.NO_RESOURCE_FOUND, FieldName.USER, emailAddress)));
|
||||
})
|
||||
.zipWith(organizationMono)
|
||||
.flatMap(tuple -> {
|
||||
User userFromDb = tuple.getT1();
|
||||
OrganizationConfiguration organizationConfiguration =
|
||||
tuple.getT2().getOrganizationConfiguration();
|
||||
boolean isStrongPasswordPolicyEnabled = organizationConfiguration != null
|
||||
&& Boolean.TRUE.equals(organizationConfiguration.getIsStrongPasswordPolicyEnabled());
|
||||
|
||||
if (!validateUserPassword(user.getPassword(), isStrongPasswordPolicyEnabled)) {
|
||||
return isStrongPasswordPolicyEnabled
|
||||
? Mono.error(new AppsmithException(
|
||||
AppsmithError.INSUFFICIENT_PASSWORD_STRENGTH,
|
||||
LOGIN_PASSWORD_MIN_LENGTH,
|
||||
LOGIN_PASSWORD_MAX_LENGTH))
|
||||
: Mono.error(new AppsmithException(
|
||||
AppsmithError.INVALID_PASSWORD_LENGTH,
|
||||
LOGIN_PASSWORD_MIN_LENGTH,
|
||||
LOGIN_PASSWORD_MAX_LENGTH));
|
||||
}
|
||||
if (!validateUserPassword(user.getPassword(), isStrongPasswordPolicyEnabled)) {
|
||||
return isStrongPasswordPolicyEnabled
|
||||
? Mono.error(new AppsmithException(
|
||||
AppsmithError.INSUFFICIENT_PASSWORD_STRENGTH,
|
||||
LOGIN_PASSWORD_MIN_LENGTH,
|
||||
LOGIN_PASSWORD_MAX_LENGTH))
|
||||
: Mono.error(new AppsmithException(
|
||||
AppsmithError.INVALID_PASSWORD_LENGTH,
|
||||
LOGIN_PASSWORD_MIN_LENGTH,
|
||||
LOGIN_PASSWORD_MAX_LENGTH));
|
||||
}
|
||||
|
||||
// User has verified via the forgot password token verfication route. Allow the user to set
|
||||
// new password.
|
||||
userFromDb.setPasswordResetInitiated(false);
|
||||
userFromDb.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
// User has verified via the forgot password token verfication route. Allow the user to set
|
||||
// new password.
|
||||
userFromDb.setPasswordResetInitiated(false);
|
||||
userFromDb.setPassword(passwordEncoder.encode(user.getPassword()));
|
||||
|
||||
// If the user has been invited but has not signed up yet, and is following the route of
|
||||
// reset
|
||||
// password flow to set up their password, enable the user's account as well
|
||||
userFromDb.setIsEnabled(true);
|
||||
// If the user has been invited but has not signed up yet, and is following the route of
|
||||
// reset
|
||||
// password flow to set up their password, enable the user's account as well
|
||||
userFromDb.setIsEnabled(true);
|
||||
|
||||
return organizationService
|
||||
.getCurrentUserOrganizationId()
|
||||
.flatMap(
|
||||
organizationId -> passwordResetTokenRepository.findByEmailAndOrganizationId(
|
||||
userFromDb.getEmail(), organizationId))
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(
|
||||
AppsmithError.NO_RESOURCE_FOUND,
|
||||
FieldName.TOKEN,
|
||||
emailTokenDTO.getToken())))
|
||||
.flatMap(passwordResetTokenRepository::delete)
|
||||
.then(repository.save(userFromDb))
|
||||
.doOnSuccess(result -> {
|
||||
// In a separate thread, we delete all other sessions of this user.
|
||||
sessionUserService
|
||||
.logoutAllSessions(userFromDb.getEmail())
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.subscribe();
|
||||
return organizationService
|
||||
.getCurrentUserOrganizationId()
|
||||
.flatMap(organizationId -> passwordResetTokenRepository.findByEmailAndOrganizationId(
|
||||
userFromDb.getEmail(), organizationId))
|
||||
.switchIfEmpty(Mono.error(new AppsmithException(
|
||||
AppsmithError.NO_RESOURCE_FOUND, FieldName.TOKEN, emailTokenDTO.getToken())))
|
||||
.flatMap(passwordResetTokenRepository::delete)
|
||||
.then(repository.save(userFromDb))
|
||||
.doOnSuccess(result -> {
|
||||
// In a separate thread, we delete all other sessions of this user.
|
||||
sessionUserService
|
||||
.logoutAllSessions(userFromDb.getEmail())
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.subscribe();
|
||||
|
||||
// we reset the counter for user's login attempts once password is reset
|
||||
rateLimitService
|
||||
.resetCounter(
|
||||
RateLimitConstants.BUCKET_KEY_FOR_LOGIN_API,
|
||||
userFromDb.getEmail())
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.subscribe();
|
||||
})
|
||||
.thenReturn(true);
|
||||
}));
|
||||
// we reset the counter for user's login attempts once password is reset
|
||||
rateLimitService
|
||||
.resetCounter(
|
||||
RateLimitConstants.BUCKET_KEY_FOR_LOGIN_API, userFromDb.getEmail())
|
||||
.subscribeOn(Schedulers.boundedElastic())
|
||||
.subscribe();
|
||||
})
|
||||
.thenReturn(true);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -696,7 +698,7 @@ public class UserServiceCEImpl extends BaseService<UserRepository, User, String>
|
|||
.flatMap(user -> updateWithoutPermission(user.getId(), updates)
|
||||
.then(
|
||||
exchange == null
|
||||
? repository.findByEmail(user.getEmail())
|
||||
? findByEmail(user.getEmail())
|
||||
: sessionUserService.refreshCurrentUser(exchange)))
|
||||
.cache();
|
||||
monos.add(updatedUserMono.then());
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.appsmith.server.solutions;
|
||||
|
||||
import com.appsmith.server.configurations.CommonConfig;
|
||||
import com.appsmith.server.helpers.UserOrganizationHelper;
|
||||
import com.appsmith.server.repositories.UserRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.CaptchaService;
|
||||
|
|
@ -28,8 +29,8 @@ public class UserAndAccessManagementServiceImpl extends UserAndAccessManagementS
|
|||
PermissionGroupPermission permissionGroupPermission,
|
||||
EmailService emailService,
|
||||
CommonConfig commonConfig,
|
||||
UserOrganizationHelper userOrganizationHelper,
|
||||
CaptchaService captchaService) {
|
||||
|
||||
super(
|
||||
sessionUserService,
|
||||
permissionGroupService,
|
||||
|
|
@ -40,6 +41,7 @@ public class UserAndAccessManagementServiceImpl extends UserAndAccessManagementS
|
|||
permissionGroupPermission,
|
||||
emailService,
|
||||
commonConfig,
|
||||
userOrganizationHelper,
|
||||
captchaService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import com.appsmith.server.domains.Workspace;
|
|||
import com.appsmith.server.dtos.InviteUsersDTO;
|
||||
import com.appsmith.server.exceptions.AppsmithError;
|
||||
import com.appsmith.server.exceptions.AppsmithException;
|
||||
import com.appsmith.server.helpers.UserOrganizationHelper;
|
||||
import com.appsmith.server.helpers.ValidationUtils;
|
||||
import com.appsmith.server.repositories.UserRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
|
|
@ -47,7 +48,7 @@ public class UserAndAccessManagementServiceCEImpl implements UserAndAccessManage
|
|||
private final UserService userService;
|
||||
private final PermissionGroupPermission permissionGroupPermission;
|
||||
private final EmailService emailService;
|
||||
private final CommonConfig commonConfig;
|
||||
private final UserOrganizationHelper userOrganizationHelper;
|
||||
|
||||
private final CaptchaService captchaService;
|
||||
|
||||
|
|
@ -61,6 +62,7 @@ public class UserAndAccessManagementServiceCEImpl implements UserAndAccessManage
|
|||
PermissionGroupPermission permissionGroupPermission,
|
||||
EmailService emailService,
|
||||
CommonConfig commonConfig,
|
||||
UserOrganizationHelper userOrganizationHelper,
|
||||
CaptchaService captchaService) {
|
||||
|
||||
this.sessionUserService = sessionUserService;
|
||||
|
|
@ -71,7 +73,7 @@ public class UserAndAccessManagementServiceCEImpl implements UserAndAccessManage
|
|||
this.userService = userService;
|
||||
this.emailService = emailService;
|
||||
this.permissionGroupPermission = permissionGroupPermission;
|
||||
this.commonConfig = commonConfig;
|
||||
this.userOrganizationHelper = userOrganizationHelper;
|
||||
this.captchaService = captchaService;
|
||||
}
|
||||
|
||||
|
|
@ -160,8 +162,10 @@ public class UserAndAccessManagementServiceCEImpl implements UserAndAccessManage
|
|||
eventData.put(FieldName.WORKSPACE, workspace);
|
||||
List<PermissionGroup> defaultPermissionGroups = tuple.getT3();
|
||||
|
||||
Mono<User> getUserFromDbAndCheckIfUserExists = userRepository
|
||||
.findByEmail(username)
|
||||
Mono<User> getUserFromDbAndCheckIfUserExists = userOrganizationHelper
|
||||
.getCurrentUserOrganizationId()
|
||||
.flatMap(organizationId ->
|
||||
userRepository.findByEmailAndOrganizationId(username, organizationId))
|
||||
.flatMap(user -> throwErrorIfUserAlreadyExistsInWorkspace(user, defaultPermissionGroups)
|
||||
.thenReturn(user));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.appsmith.server.solutions.ce_compatible;
|
||||
|
||||
import com.appsmith.server.configurations.CommonConfig;
|
||||
import com.appsmith.server.helpers.UserOrganizationHelper;
|
||||
import com.appsmith.server.repositories.UserRepository;
|
||||
import com.appsmith.server.services.AnalyticsService;
|
||||
import com.appsmith.server.services.CaptchaService;
|
||||
|
|
@ -16,6 +17,7 @@ import org.springframework.stereotype.Component;
|
|||
@Component
|
||||
public class UserAndAccessManagementServiceCECompatibleImpl extends UserAndAccessManagementServiceCEImpl
|
||||
implements UserAndAccessManagementServiceCECompatible {
|
||||
|
||||
public UserAndAccessManagementServiceCECompatibleImpl(
|
||||
SessionUserService sessionUserService,
|
||||
PermissionGroupService permissionGroupService,
|
||||
|
|
@ -26,6 +28,7 @@ public class UserAndAccessManagementServiceCECompatibleImpl extends UserAndAcces
|
|||
PermissionGroupPermission permissionGroupPermission,
|
||||
EmailService emailService,
|
||||
CommonConfig commonConfig,
|
||||
UserOrganizationHelper userOrganizationHelper,
|
||||
CaptchaService captchaService) {
|
||||
super(
|
||||
sessionUserService,
|
||||
|
|
@ -37,6 +40,7 @@ public class UserAndAccessManagementServiceCECompatibleImpl extends UserAndAcces
|
|||
permissionGroupPermission,
|
||||
emailService,
|
||||
commonConfig,
|
||||
userOrganizationHelper,
|
||||
captchaService);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user