All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.n2oapp.security.admin.impl.service.UserServiceImpl Maven / Gradle / Ivy

There is a newer version: 8.0.1
Show newest version
package net.n2oapp.security.admin.impl.service;

import net.n2oapp.platform.i18n.UserException;
import net.n2oapp.security.admin.api.audit.AuditService;
import net.n2oapp.security.admin.api.criteria.UserCriteria;
import net.n2oapp.security.admin.api.model.*;
import net.n2oapp.security.admin.api.provider.SsoUserRoleProvider;
import net.n2oapp.security.admin.api.service.MailService;
import net.n2oapp.security.admin.api.service.UserService;
import net.n2oapp.security.admin.impl.entity.AccountEntity;
import net.n2oapp.security.admin.impl.entity.RegionEntity;
import net.n2oapp.security.admin.impl.entity.UserEntity;
import net.n2oapp.security.admin.impl.repository.UserRepository;
import net.n2oapp.security.admin.impl.service.specification.UserSpecifications;
import net.n2oapp.security.admin.impl.util.PasswordGenerator;
import net.n2oapp.security.admin.impl.util.UserValidations;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;

import javax.ws.rs.NotFoundException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.Objects.isNull;
import static java.util.Objects.nonNull;
import static org.springframework.util.StringUtils.hasText;

/**
 * Реализация сервиса управления пользователями
 */
@Transactional
public class UserServiceImpl implements UserService {
    private static final String ID = "id";
    private static final String USERNAME = "username";
    private final UserRepository userRepository;
    private final SsoUserRoleProvider provider;

    @Autowired
    private PasswordGenerator passwordGenerator;
    @Autowired
    private MailService mailService;
    @Autowired
    private UserValidations userValidations;
    @Autowired
    private AuditService auditService;

    @Value("${access.user.send-mail-delete-user:false}")
    private Boolean sendMailDelete;

    @Value("${access.user.send-mail-activate-user:false}")
    private Boolean sendMailActivate;

    @Value("${access.email-as-username:false}")
    private Boolean emailAsUsername;

    public UserServiceImpl(UserRepository userRepository, SsoUserRoleProvider provider) {
        this.userRepository = userRepository;
        this.provider = provider;
    }

    @Override
    public User create(UserForm user) {
        validateUsernameEmailSnils(user);

//        todo без создания пользователя в кейклоке не имеет смысла, оставлено для тестов
        String password = (user.getPassword() != null) ? user.getPassword() : user.getTemporaryPassword();
        if (nonNull(user.getPassword()))
            userValidations.checkPassword(password, user.getPasswordCheck(), user.getId());
        if (isNull(password)) {
            password = passwordGenerator.generate();
            user.setTemporaryPassword(password);
        }

        UserEntity savedUser = userRepository.save(entityForm(new UserEntity(), user));

        if (Boolean.TRUE.equals(user.getSendOnEmail()) && user.getEmail() != null) {
            mailService.sendWelcomeMail(user);
        }

        return audit("audit.userCreate", model(savedUser));
    }

    @Override
    public User register(UserRegisterForm user) {
        UserForm form = new UserForm();
        form.setEmail(user.getEmail());
        form.setUsername(user.getUsername());
        form.setPassword(user.getPassword());
        form.setPasswordCheck(user.getPassword());
        form.setName(user.getName());
        form.setSurname(user.getSurname());
        form.setPatronymic(user.getPatronymic());
        form.setSendOnEmail(user.getSendPasswordToEmail());
        form.setIsActive(user.getIsActive() != null ? user.getIsActive() : true);
        form.setExpirationDate(user.getExpirationDate());
        return create(form);
    }

    @Override
    public User update(UserForm user) {
        return doUpdate(user);
    }

    @Override
    public User patch(Map userInfo) {
        if (userInfo == null)
            throw new UserException("exception.wrongRequest");

        if (!userInfo.containsKey(ID) && !userInfo.containsKey(USERNAME))
            throw new UserException("exception.userWithoutIdAndUsername");

        UserEntity entity = null;
        if (userInfo.containsKey(ID) && nonNull(userInfo.get(ID))) {
            entity = userRepository.findById(Integer.parseInt(userInfo.get(ID).toString())).orElse(null);
        }
        if (isNull(entity) && userInfo.containsKey(USERNAME) && nonNull(userInfo.get(USERNAME))) {
            entity = userRepository.findOneByUsernameIgnoreCase(userInfo.get(USERNAME).toString());
        }

        if (isNull(entity))
            throw new NotFoundException();

        UserForm user = obtainUserForm(entity, userInfo);
        return doUpdate(user);
    }

    public User doUpdate(UserForm user) {
        validateUsernameEmailSnils(user);
        if (nonNull(user.getPassword())) {
            userValidations.checkPassword(user.getPassword(), user.getPasswordCheck(), user.getId());
        }
        UserEntity entityUser = userRepository.getReferenceById(user.getId());
        boolean isActiveChanged = false;
        if (nonNull(user.getIsActive()))
            isActiveChanged = !Objects.equals(entityUser.getIsActive(), user.getIsActive());
        if (entityUser.getUsername().equals(getContextUserName()) && isActiveChanged) {
            throw new UserException("exception.selfChangeActivity");
        }
        entityUser = entityForm(entityUser, user);
        // кодируем пароль перед сохранением в бд если он изменился
        UserEntity updatedUser = userRepository.save(entityUser);
        User result = model(updatedUser);
        if (sendMailActivate && isActiveChanged) {
            mailService.sendChangeActivateMail(result);
        }
        return audit("audit.userUpdate", result);
    }

    @Override
    public void delete(Integer id) {
        SsoUser user = model(userRepository.findById(id).orElseThrow(() -> new UserException("exception.userNotFound")));
        if (nonNull(user) && user.getUsername().equals(getContextUserName())) {
            throw new UserException("exception.selfDelete");
        }
        userRepository.deleteById(id);
        if (nonNull(user)) {
            if (sendMailDelete)
                mailService.sendUserDeletedMail(user);
            audit("audit.userDelete", user);
        }
    }

    @Override
    public User getById(Integer id) {
        UserEntity entity = userRepository.findById(id).orElse(null);
        return model(entity);
    }

    @Override
    public Page findAll(UserCriteria criteria) {
        if (criteria.getRoleIds() != null)
            criteria.setRoleIds(criteria.getRoleIds().stream().filter(roleId -> roleId > 0).collect(Collectors.toList()));
        final Specification specification = new UserSpecifications(criteria);
        if (criteria.getOrders() == null)
            criteria.setOrders(new ArrayList<>());
        if (criteria.getOrders().stream().map(Sort.Order::getProperty).anyMatch("fio"::equals)) {
            Sort.Direction orderFio = criteria.getOrders().stream().filter(o -> o.getProperty().equals("fio")).findAny().get().getDirection();
            criteria.getOrders().add(new Sort.Order(orderFio, "surname"));
            criteria.getOrders().add(new Sort.Order(orderFio, "name"));
            criteria.getOrders().add(new Sort.Order(orderFio, "patronymic"));
            criteria.getOrders().removeIf(s -> s.getProperty().equals("fio"));
        }
        criteria.getOrders().add(new Sort.Order(Sort.Direction.ASC, "id"));
        final Page all = userRepository.findAll(specification, criteria);
        return all.map(this::model);
    }

    @Override
    public User changeActive(Integer id) {
        UserEntity userEntity = userRepository.findById(id).orElse(null);
        if (nonNull(userEntity) && userEntity.getUsername().equals(getContextUserName())) {
            throw new UserException("exception.selfChangeActivity");
        }
        userEntity.setIsActive(!userEntity.getIsActive());
        SsoUser result = model(userRepository.save(userEntity));

        List accounts = userEntity.getAccounts();
        if (nonNull(accounts) && accounts.stream().anyMatch(a -> provider.isSupports(a.getExternalSystem())))
            provider.changeActivity(result);

        if (sendMailActivate) {
            mailService.sendChangeActivateMail(model(userEntity));
        }

        return audit("audit.userChangeActive", result);
    }

    @Override
    public Boolean checkUniqueUsername(String username) {
        return userRepository.findOneByUsernameIgnoreCase(username) == null;
    }

    @Override
    public User loadSimpleDetails(Integer id) {
        User simpleUser = new User();

        if (id != null) {
            User user = getById(id);

            if (user != null) {
                simpleUser.setId(id);
                simpleUser.setUsername(user.getUsername());
                simpleUser.setEmail(user.getEmail());
            }
        }

        simpleUser.setTemporaryPassword(passwordGenerator.generate());
        return simpleUser;
    }

    @Override
    public void resetPassword(UserForm user) {
        if (nonNull(user.getEmail())) {
            userValidations.checkEmail(user.getEmail());
        }
        // используем либо установленный пользователем, либо сгенерированный пароль
        String password = (user.getPassword() != null) ? user.getPassword() : user.getTemporaryPassword();
        if (nonNull(user.getPassword())) {
            userValidations.checkPassword(password, user.getPasswordCheck(), user.getId());
        }

        UserEntity userEntity = null;
        if (user.getId() != null)
            userEntity = userRepository.getReferenceById(user.getId());
        if (userEntity == null && user.getEmail() != null)
            userEntity = userRepository.findOneByEmailIgnoreCase(user.getEmail());
        if (userEntity == null && user.getUsername() != null)
            userEntity = userRepository.findOneByUsernameIgnoreCase(user.getUsername());
        if (userEntity == null && user.getSnils() != null)
            userEntity = userRepository.findOneBySnilsIgnoreCase(user.getSnils()).orElse(null);

        if (userEntity != null) {
            user.setEmail(userEntity.getEmail());
            user.setUsername(userEntity.getUsername());
            user.setName(userEntity.getName());
            user.setSurname(userEntity.getSurname());
            user.setPatronymic(userEntity.getPatronymic());
            if (isNull(password)) {
                password = passwordGenerator.generate();
            }
            userRepository.save(userEntity);

            if (Boolean.TRUE.equals(user.getSendOnEmail()) && nonNull(user.getEmail())) {
                mailService.sendResetPasswordMail(user);
            }
        }
    }

    @Override
    public Password generatePassword() {
        Password result = new Password();
        result.password = passwordGenerator.generate();
        return result;
    }

    public void setEmailAsUsername(Boolean emailAsUsername) {
        this.emailAsUsername = emailAsUsername;
    }

    private UserEntity entityForm(UserEntity entity, UserForm model) {
        entity.setUsername(model.getUsername());
        entity.setName(model.getName());
        entity.setSurname(model.getSurname());
        entity.setPatronymic(model.getPatronymic());
        entity.setIsActive(model.getIsActive());
        entity.setEmail(model.getEmail());
        entity.setSnils(model.getSnils());
        entity.setExpirationDate(model.getExpirationDate());
        return entity;
    }

    private String getContextUserName() {
        if (nonNull(SecurityContextHolder.getContext()) &&
                nonNull(SecurityContextHolder.getContext().getAuthentication()) &&
                SecurityContextHolder.getContext().getAuthentication().getPrincipal()
                        instanceof org.springframework.security.core.userdetails.User) {
            return ((org.springframework.security.core.userdetails.User)
                    SecurityContextHolder.getContext().getAuthentication().getPrincipal()).getUsername();
        }

        return null;
    }

    private SsoUser model(UserEntity entity) {
        if (isNull(entity)) return null;
        SsoUser model = new SsoUser();
        model.setId(entity.getId());
        model.setUsername(entity.getUsername());
        model.setName(entity.getName());
        model.setSurname(entity.getSurname());
        model.setPatronymic(entity.getPatronymic());
        model.setIsActive(entity.getIsActive());
        model.setEmail(entity.getEmail());
        model.setSnils(entity.getSnils());
        model.setExpirationDate(entity.getExpirationDate());
        model.setRegion(model(entity.getRegion()));

        StringJoiner joiner = new StringJoiner(" ");
        if (nonNull(entity.getSurname()))
            joiner.add(entity.getSurname());
        if (nonNull(entity.getName()))
            joiner.add(entity.getName());
        if (nonNull(entity.getPatronymic()))
            joiner.add(entity.getPatronymic());
        String fio = joiner.toString();
        model.setFio(hasText(fio) ? fio : null);

        return model;
    }

    private Region model(RegionEntity entity) {
        if (isNull(entity)) return null;
        Region region = new Region();
        region.setId(entity.getId());
        region.setName(entity.getName());
        region.setCode(entity.getCode());
        region.setOkato(entity.getOkato());
        return region;
    }

    private void validateUsernameEmailSnils(UserForm user) {
        if (!Boolean.TRUE.equals(emailAsUsername)) {
            userValidations.checkUsernameUniq(user.getId(), model(userRepository.findOneByUsernameIgnoreCase(user.getUsername())));
            userValidations.checkUsername(user.getUsername());
        } else {
            userValidations.checkEmailUniq(user.getId(), model(userRepository.findOneByEmailIgnoreCase(user.getEmail())));
            user.setUsername(user.getEmail());
        }
        if (nonNull(user.getEmail()))
            userValidations.checkEmail(user.getEmail());
        if (nonNull(user.getSnils()))
            userValidations.checkSnils(user.getSnils());
    }

    private User audit(String action, User user) {
        auditService.audit(action, user, "" + user.getId(), "audit.user");
        return user;
    }

    private UserForm obtainUserForm(UserEntity entity, Map userInfo) {
        UserForm userForm = new UserForm();
        userForm.setId((Integer) userInfo.getOrDefault(ID, entity.getId()));
        userForm.setUsername((String) userInfo.getOrDefault(USERNAME, entity.getUsername()));
        userForm.setEmail((String) userInfo.getOrDefault("email", entity.getEmail()));
        userForm.setSurname((String) userInfo.getOrDefault("surname", entity.getSurname()));
        userForm.setName((String) userInfo.getOrDefault("name", entity.getName()));
        userForm.setPatronymic((String) userInfo.getOrDefault("patronymic", entity.getPatronymic()));
        userForm.setPassword((String) userInfo.getOrDefault("password", null));
        userForm.setPasswordCheck((String) userInfo.getOrDefault("passwordCheck", null));
        userForm.setTemporaryPassword((String) userInfo.getOrDefault("temporaryPassword", null));
        userForm.setSendOnEmail((Boolean) userInfo.getOrDefault("sendOnEmail", false));
        userForm.setIsActive((Boolean) userInfo.getOrDefault("isActive", entity.getIsActive()));
        userForm.setSnils((String) userInfo.getOrDefault("snils", entity.getSnils()));
        userForm.setExpirationDate((LocalDateTime) userInfo.getOrDefault("expirationDate", null));
        return userForm;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy