email is unique for registered user

This commit is contained in:
Lucio Lelii 2026-03-26 13:50:39 +01:00
parent eb66452f03
commit 5461e0250f
6 changed files with 49 additions and 5 deletions

View File

@ -3,6 +3,7 @@ package it.cnr.isti.workflow.manager.auth.model;
public enum CreateUserResult {
SUCCESS,
USER_ALREADY_EXISTS,
EMAIL_ALREADY_EXISTS,
INVALID_EMAIL,
INVALID_PASSWORD
}

View File

@ -28,4 +28,7 @@ public interface AuthRepository extends JpaRepository<LoginEntity, String> {
@Query("select u from LoginEntity u where u.active is null or u.active = true")
List<LoginEntity> findByActiveTrue();
@Query("select case when count(u) > 0 then true else false end from LoginEntity u where lower(u.email) = lower(:email)")
boolean existsByEmailIgnoreCase(@Param("email") String email);
}

View File

@ -1,6 +1,7 @@
package it.cnr.isti.workflow.manager.auth.repo;
import it.cnr.isti.workflow.manager.auth.model.UserRole;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
@ -17,6 +18,7 @@ public class LoginEntity {
@Id
private String username;
private String password;
@Column(unique = true)
private String email;
private Boolean active;
@Enumerated(EnumType.STRING)

View File

@ -49,14 +49,18 @@ public class AuthService {
if (authRepository.existsById(username)) {
return CreateUserResult.USER_ALREADY_EXISTS;
}
if (!isValidEmail(email)) {
String normalizedEmail = normalizeEmail(email);
if (!isValidEmail(normalizedEmail)) {
return CreateUserResult.INVALID_EMAIL;
}
if (authRepository.existsByEmailIgnoreCase(normalizedEmail)) {
return CreateUserResult.EMAIL_ALREADY_EXISTS;
}
if (!isValidPassword(password)) {
return CreateUserResult.INVALID_PASSWORD;
}
String hashedPassword = hashPassword(password);
authRepository.save(new LoginEntity(username, hashedPassword, email.trim(), role == null ? UserRole.USER : role));
authRepository.save(new LoginEntity(username, hashedPassword, normalizedEmail, role == null ? UserRole.USER : role));
return CreateUserResult.SUCCESS;
}
@ -164,7 +168,7 @@ public class AuthService {
if (email == null) {
return false;
}
String normalizedEmail = email.trim();
String normalizedEmail = normalizeEmail(email);
if (normalizedEmail.isEmpty() || normalizedEmail.contains(" ")) {
return false;
}
@ -177,4 +181,8 @@ public class AuthService {
&& dotIndex < normalizedEmail.length() - 1;
}
private String normalizeEmail(String email) {
return email == null ? null : email.trim().toLowerCase(java.util.Locale.ROOT);
}
}

View File

@ -90,7 +90,8 @@ public class AuthController {
CreateUserResult result = authService.registerUser(request.getUsername(), request.getPassword(), request.getEmail());
return switch (result) {
case SUCCESS -> ResponseEntity.ok().build();
case USER_ALREADY_EXISTS -> ResponseEntity.badRequest().body("the user already exists");
case USER_ALREADY_EXISTS -> ResponseEntity.badRequest().body("USER_ALREADY_EXISTS");
case EMAIL_ALREADY_EXISTS -> ResponseEntity.badRequest().body("EMAIL_ALREADY_EXISTS");
case INVALID_EMAIL -> ResponseEntity.badRequest().body("INVALID_EMAIL");
case INVALID_PASSWORD -> ResponseEntity.badRequest().body("INVALID_PASSWORD");
};
@ -140,7 +141,8 @@ public class AuthController {
CreateUserResult result = authService.createUser(request.username(), request.password(), request.email(), request.role());
return switch (result) {
case SUCCESS -> ResponseEntity.ok().build();
case USER_ALREADY_EXISTS -> ResponseEntity.badRequest().body("the user already exists");
case USER_ALREADY_EXISTS -> ResponseEntity.badRequest().body("USER_ALREADY_EXISTS");
case EMAIL_ALREADY_EXISTS -> ResponseEntity.badRequest().body("EMAIL_ALREADY_EXISTS");
case INVALID_EMAIL -> ResponseEntity.badRequest().body("INVALID_EMAIL");
case INVALID_PASSWORD -> ResponseEntity.badRequest().body("INVALID_PASSWORD");
};

View File

@ -303,6 +303,34 @@ public class AuthControllerTest {
assert "INVALID_EMAIL".equals(response.getBody());
}
@Test
public void registerRejectsDuplicateEmail() {
String email = "duplicate-" + uniqueSuffix() + "@example.com";
ResponseEntity<?> firstResponse = authController.register(
new AuthRequest("first-" + uniqueSuffix(), "Validpass1!", email));
assert firstResponse.getStatusCode().is2xxSuccessful();
ResponseEntity<?> secondResponse = authController.register(
new AuthRequest("second-" + uniqueSuffix(), "Validpass1!", email.toUpperCase(java.util.Locale.ROOT)));
assert secondResponse.getStatusCode() == HttpStatus.BAD_REQUEST;
assert "EMAIL_ALREADY_EXISTS".equals(secondResponse.getBody());
}
@Test
public void registerRejectsDuplicateUsername() {
String username = "duplicate-user-" + uniqueSuffix();
ResponseEntity<?> firstResponse = authController.register(
new AuthRequest(username, "Validpass1!", username + "@example.com"));
assert firstResponse.getStatusCode().is2xxSuccessful();
ResponseEntity<?> secondResponse = authController.register(
new AuthRequest(username, "Validpass1!", "other-" + uniqueSuffix() + "@example.com"));
assert secondResponse.getStatusCode() == HttpStatus.BAD_REQUEST;
assert "USER_ALREADY_EXISTS".equals(secondResponse.getBody());
}
@Test
public void adminEndpointsAcceptJwtAdminRole() throws Exception {
String username = "jwtadmin-" + uniqueSuffix();