KeycloakUserRepositoryImpl.java

package net.andresbustamante.yafoot.users.repository.impl;

import jakarta.ws.rs.WebApplicationException;
import net.andresbustamante.yafoot.commons.exceptions.DirectoryException;
import net.andresbustamante.yafoot.users.model.User;
import net.andresbustamante.yafoot.users.repository.UserRepository;
import org.apache.commons.collections4.CollectionUtils;
import org.keycloak.admin.client.Keycloak;
import org.keycloak.admin.client.resource.RealmResource;
import org.keycloak.admin.client.resource.UserResource;
import org.keycloak.admin.client.resource.UsersResource;
import org.keycloak.representations.idm.UserRepresentation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Optional;

@Component
public class KeycloakUserRepositoryImpl implements UserRepository {

    private final Keycloak keycloak;

    @Value("${app.keycloak.server.realm}")
    private String realm;

    public KeycloakUserRepositoryImpl(final Keycloak keycloak) {
        this.keycloak = keycloak;
    }

    @Override
    public void updateUser(final User user) throws DirectoryException {
        try {
            Optional<UserRepresentation> userRepresentationOptional = findUser(user.getEmail());

            if (userRepresentationOptional.isPresent()) {
                UserRepresentation userRepresentation = userRepresentationOptional.get();

                String userId = userRepresentation.getId();

                copyUserData(user, userRepresentation);

                RealmResource realmResource = keycloak.realm(realm);
                UsersResource usersResource = realmResource.users();

                UserResource userResource = usersResource.get(userId);
                userResource.update(userRepresentation);
            }
        } catch (WebApplicationException e) {
            throw new DirectoryException(e.getMessage());
        }
    }

    @Override
    public void deleteUser(final User user) throws DirectoryException {
        try {
            Optional<UserRepresentation> userRepresentationOptional = findUser(user.getEmail());

            if (userRepresentationOptional.isPresent()) {
                UserRepresentation userRepresentation = userRepresentationOptional.get();

                String userId = userRepresentation.getId();

                RealmResource realmResource = keycloak.realm(realm);
                UsersResource usersResource = realmResource.users();

                UserResource userResource = usersResource.get(userId);
                userResource.remove();
            }
        } catch (WebApplicationException e) {
            throw new DirectoryException(e.getMessage());
        }
    }

    @Override
    public User findUserByEmail(final String email) throws DirectoryException {
        try {
            Optional<UserRepresentation> userRepresentationOptional = findUser(email);

            if (userRepresentationOptional.isPresent()) {
                User user = new User();
                copyUserData(userRepresentationOptional.get(), user);
                return user;
            }
            return null;
        } catch (WebApplicationException e) {
            throw new DirectoryException(e.getMessage());
        }
    }

    private Optional<UserRepresentation> findUser(final String email) {
        RealmResource realmResource = keycloak.realm(realm);
        UsersResource usersResource = realmResource.users();

        List<UserRepresentation> directoryUsers = usersResource.searchByEmail(email, false);

        if (CollectionUtils.isNotEmpty(directoryUsers)) {
            return directoryUsers.stream().filter(u -> email.equalsIgnoreCase(u.getEmail())).findFirst();
        }

        return Optional.empty();
    }

    private void copyUserData(final User source, final UserRepresentation destination) {
        destination.setFirstName(source.getFirstName());
        destination.setLastName(source.getSurname());
    }

    private void copyUserData(final UserRepresentation source, final User destination) {
        destination.setFirstName(source.getFirstName());
        destination.setSurname(source.getLastName());
    }
}