Pull request #668: RED-6548 - Username not saved / Email saved as username

Merge in RED/persistence-service from bugfix/RED-6548 to master

* commit '47df255e12a67059bf9f318fe03756ea15fa0d28':
  RED-6362 - Cannot add KMS signature - rework after review
  RED-6548 - Username not saved / Email saved as username - extend createUserRequest with username - update the username with the one provided - update also the username in case of updating profile with a new email address
This commit is contained in:
Corina Olariu 2023-04-13 14:45:45 +02:00
commit 413ff8fa8a
2 changed files with 34 additions and 14 deletions

View File

@ -31,6 +31,7 @@ import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl;
import org.keycloak.OAuth2Constants;
import org.keycloak.admin.client.KeycloakBuilder;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.CredentialRepresentation;
import org.keycloak.representations.idm.RoleRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
@ -92,24 +93,29 @@ public class UserService {
@CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true)
public User createUser(CreateUserRequest user) {
if (!realmService.realm(TenantContext.getTenantId()).users().search(user.getEmail()).isEmpty()) {
String username = StringUtils.isEmpty(user.getUsername()) ? user.getEmail() : user.getUsername();
if (!this.getTenantUsersResource().search(username).isEmpty()) {
throw new ConflictException("User with this username already exists");
}
if (!EmailValidator.getInstance().isValid(user.getEmail())) {
throw new BadRequestException("Email address format is not valid");
}
// also search by email in case the username was provided at creation
if (!StringUtils.isEmpty(user.getUsername()) && !this.getTenantUsersResource().searchByEmail(user.getEmail(), true).isEmpty()) {
throw new ConflictException("User with this email already exists");
}
validateRoles(user.getRoles());
UserRepresentation userRepresentation = new UserRepresentation();
userRepresentation.setUsername(user.getEmail());
userRepresentation.setUsername(username);
userRepresentation.setEmail(user.getEmail());
userRepresentation.setEnabled(true);
userRepresentation.setFirstName(user.getFirstName());
userRepresentation.setLastName(user.getLastName());
try (var response = realmService.realm(TenantContext.getTenantId()).users().create(userRepresentation)) {
try (var response = this.getTenantUsersResource().create(userRepresentation)) {
if (response.getStatusInfo().getFamily() != Response.Status.Family.SUCCESSFUL) {
if (response.getStatusInfo().getStatusCode() == 409) {
@ -121,7 +127,7 @@ public class UserService {
throw new BadRequestException("Cannot create user ... ");
}
var createdUser = getUserByUsername(user.getEmail());
var createdUser = getUserByUsername(username);
try {
sendResetPasswordEmail(createdUser.getUserId());
@ -142,14 +148,18 @@ public class UserService {
customPermissionService.syncAllCustomPermissions();
return getUserByUsername(user.getEmail());
return getUserByUsername(username);
}
}
private UsersResource getTenantUsersResource() {
return realmService.realm(TenantContext.getTenantId()).users();
}
private User getUserByUsername(String username) {
var userList = realmService.realm(TenantContext.getTenantId()).users().search(username);
var userList = this.getTenantUsersResource().search(username);
if (userList.isEmpty()) {
throw new NotFoundException("User with this username already exists");
}
@ -161,7 +171,7 @@ public class UserService {
private void sendResetPasswordEmail(String userId) {
try {
realmService.realm(TenantContext.getTenantId()).users().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400);
this.getTenantUsersResource().get(userId).executeActionsEmail(Collections.singletonList("UPDATE_PASSWORD"), 86400);
} catch (Exception e) {
throw new BadRequestException("Failed to send email", e);
}
@ -252,7 +262,7 @@ public class UserService {
throw new BadRequestException("No id provided.");
}
try {
return realmService.realm(TenantContext.getTenantId()).users().get(userId);
return this.getTenantUsersResource().get(userId);
} catch (NotFoundException e) {
throw new NotFoundException("User with id: " + userId + " does not exist", e);
}
@ -286,7 +296,7 @@ public class UserService {
private Set<String> getRoles(String id) {
List<RoleRepresentation> realmMappings = realmService.realm(TenantContext.getTenantId()).users().get(id).roles().getAll().getRealmMappings();
List<RoleRepresentation> realmMappings = this.getTenantUsersResource().get(id).roles().getAll().getRealmMappings();
if (realmMappings == null) {
log.warn("User with id=" + id + " contains null role mappings.");
return new TreeSet<>();
@ -352,7 +362,7 @@ public class UserService {
@CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true)
public void updateMyProfile(UpdateMyProfileRequest updateProfileRequest) {
var user = realmService.realm(TenantContext.getTenantId()).users().get(KeycloakSecurity.getUserId());
var user = this.getUserResource(KeycloakSecurity.getUserId());
var userRepresentation = user.toRepresentation();
if (userRepresentation.getFederatedIdentities() != null && !userRepresentation.getFederatedIdentities().isEmpty() && !updateProfileRequest.getEmail()
@ -367,7 +377,7 @@ public class UserService {
userRepresentation.setFirstName(updateProfileRequest.getFirstName());
userRepresentation.setLastName(updateProfileRequest.getLastName());
userRepresentation.setEmail(updateProfileRequest.getEmail());
userRepresentation.setUsername(updateProfileRequest.getEmail());
this.setUsername(userRepresentation, updateProfileRequest.getEmail());
try {
user.update(userRepresentation);
@ -387,6 +397,12 @@ public class UserService {
.build());
}
private void setUsername(UserRepresentation userRepresentation, String emailToSet) {
// update the username only if none was provided at creation and in this case the email and username are the same
if (userRepresentation.getUsername().equals(userRepresentation.getEmail())) {
userRepresentation.setUsername(emailToSet);
}
}
private void validatePassword(String username, String password) {
@ -484,7 +500,7 @@ public class UserService {
@CacheEvict(value = USERS_CACHE, allEntries = true, beforeInvocation = true)
public void updateProfile(String userId, UpdateProfileRequest updateProfileRequest) {
var user = realmService.realm(TenantContext.getTenantId()).users().get(userId);
var user = this.getUserResource(userId);
var userRepresentation = user.toRepresentation();
if (userRepresentation.getFederatedIdentities() != null && !userRepresentation.getFederatedIdentities().isEmpty() && !updateProfileRequest.getEmail()
@ -499,6 +515,7 @@ public class UserService {
userRepresentation.setFirstName(updateProfileRequest.getFirstName());
userRepresentation.setLastName(updateProfileRequest.getLastName());
userRepresentation.setEmail(updateProfileRequest.getEmail());
this.setUsername(userRepresentation, updateProfileRequest.getEmail());
user.update(userRepresentation);
@ -516,7 +533,7 @@ public class UserService {
public User activateProfile(String userId, boolean isActive) {
var user = realmService.realm(TenantContext.getTenantId()).users().get(userId);
var user = this.getUserResource(userId);
var userRepresentation = user.toRepresentation();
userRepresentation.setEnabled(isActive);
@ -535,7 +552,7 @@ public class UserService {
.details(Map.of("Profile activated", isActive))
.build());
return convert(realmService.realm(TenantContext.getTenantId()).users().get(userId).toRepresentation());
return convert(this.getTenantUsersResource().get(userId).toRepresentation());
}

View File

@ -12,6 +12,9 @@ public class CreateUserRequest {
@Schema(description = "Email of user.")
private String email;
@Schema(description = "Username of user.")
private String username;
@Schema(description = "First name of user.")
private String firstName;