package com.megatim.fdxconsultation.core.impl.administration; import com.bekosoftware.genericdaolayer.dao.ifaces.GenericDAO; import com.bekosoftware.genericdaolayer.dao.tools.RestrictionsContainer; import com.bekosoftware.genericmanagerlayer.core.impl.AbstractGenericManager; import com.megatim.commons.tools.exceptions.ApplicationValidationException; import com.megatim.fdxcommons.model.enumeration.EtatOperation; import com.megatim.fdxcommons.model.enumeration.TypeIdMessageSysteme; import com.megatim.fdxcommons.model.enumeration.TypeMessageSysteme; import com.megatim.fdxcommons.model.enumeration.TypeOperation; import com.megatim.fdxcommons.model.pojo.CriteriaEntityFromView; import com.megatim.fdxcommons.model.pojo.CriteriaFormRequest; import com.megatim.fdxcommons.tools.exceptions.CommonAlredyExistException; import com.megatim.fdxcommons.tools.exceptions.CommonApplicationValidationException; import com.megatim.fdxcommons.tools.exceptions.CommonRessourceNotFoundException; import com.megatim.fdxconsultation.core.ifaces.administration.HistoriqueMotDePasseManager; import com.megatim.fdxconsultation.core.ifaces.administration.UserManager; import com.megatim.fdxconsultation.core.ifaces.message.systeme.MessageSystemeManager; import com.megatim.fdxconsultation.core.ifaces.stats.TableauBordManager; import com.megatim.fdxconsultation.dao.ifaces.abstracts.PaginationWithCriteriaEntityDAO; import com.megatim.fdxconsultation.dao.ifaces.administration.UserDAO; import com.megatim.fdxconsultation.model.administration.Action; import com.megatim.fdxconsultation.model.administration.Role; import com.megatim.fdxconsultation.model.administration.User; import com.megatim.fdxconsultation.reporting.model.administration.UserReporting; import com.megatim.fdxconsultation.model.dto.EditPasswordDto; import com.megatim.fdxconsultation.model.dto.UserDto; import com.megatim.fdxconsultation.model.dto.UserSlimDto; import com.megatim.fdxconsultation.model.mappers.MapStructMapper; import com.megatim.fdxconsultation.model.searchentities.UserSearch; import com.megatim.fdxconsultation.tools.CommonTools; import com.megatim.fdxconsultation.tools.CommonsToolsEntity; import com.megatim.fdxconsultation.tools.context.AppCommonContext; import com.megatim.reporting.adhoc.dto.ReportConfiguration; import com.megatim.rs.tools.utils.RestrictionContainerBuildeUtil; import java.io.File; import java.math.BigDecimal; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.enterprise.context.Dependent; import javax.inject.Inject; import javax.transaction.Transactional; @Transactional @Dependent public class UserManagerImpl extends AbstractGenericManager implements UserManager { @Inject protected UserDAO dao; @Inject protected HistoriqueMotDePasseManager historiqueMotDePasseManager; @Inject private MapStructMapper mapstructMapper; @Inject com.megatim.fdxcommons.model.mappers.MapStructMapper commonMapper; @Inject TableauBordManager tableauBordManager; @Inject private MessageSystemeManager messageSystemeManager; /** * */ public UserManagerImpl() { } @Override public GenericDAO getDao() { return dao; } @Override public String getEntityIdName() { return "id"; } @Override public UserDto getById(Long id) { return mapToDetailDto(dao.getById(id)); } public User getCurrentElement() { return dao.getCurrentUser(); } @Override @Transactional public User modify(Long id, User entity, User connectedUser) { User actualEntity = find(getEntityIdName(), id); beforeModify(actualEntity, entity, connectedUser); update(id, actualEntity); tableauBordManager.deleteUserTableauBord(entity); messageSystemeManager.ajouter(TypeMessageSysteme.AVERTISSEMENT, TypeIdMessageSysteme.MODIFICATION_INFORMATION_UTILISATEUR, "Oups ! il semblerait que vos paramètres personnels aient été mis à jour, en conséquence vous allez être déconnecté, pour que les modifications soient prises en compte, vous pourrez vous reconnecter par la suite.", actualEntity); return actualEntity; } @Override public User recuperUtilisateur(String username, String motDePasse) { return dao.recuperUtilisateur(username, motDePasse); } @Override public User recuperUtilisateur(String username) { return dao.recuperUtilisateur(username); } public User getUserByUserName(String userName) { List liste = findByUniqueProperty("userName", userName, null); if (liste != null && !liste.isEmpty()) { return liste.get(0); } else { return null; } } @Override public void validate(String userName, User utilisateurConnecte) { User entity = getUserByUserName(userName); if (entity == null) { throw new CommonRessourceNotFoundException(User.class); } entity.setEtatOperation(EtatOperation.ACTIF); entity.setDateValidation(new Date()); entity.setUtilisateurValidation(utilisateurConnecte != null ? utilisateurConnecte.getUserName() : null); update(entity.getId(), entity); } @Override public void reject(String userName, User user, User utilisateurConnecte) { User entity = getUserByUserName(userName); if (entity == null) { throw new CommonRessourceNotFoundException(User.class); } if (user.getMotifRejet() == null || user.getMotifRejet().isEmpty()) { throw new ApplicationValidationException(Arrays.asList("Le motif de rejet est obligatoire")); } entity.setEtatOperation(EtatOperation.REJETE); entity.setDateRejetValidation(new Date()); entity.setUtilisateurRejetValidation(utilisateurConnecte != null ? utilisateurConnecte.getUserName() : null); entity.setMotifRejet(user.getMotifRejet()); update(entity.getId(), entity); } @Override public UserSlimDto mapToDto(User entity) { return mapstructMapper.userToUserSlimDto(entity); } @Override public UserDto mapToDetailDto(User entity) { return mapstructMapper.userToUserDto(entity); } @Override public void beforeModify(User actualEntity, User requestEntity, User utilisateurConnecte) { if (actualEntity == null) { throw new CommonRessourceNotFoundException(User.class); } User userWithSameName = recuperUtilisateur(requestEntity.getUserName()); if (requestEntity.getUserName() != null && !requestEntity.getUserName().isEmpty() && userWithSameName != null && !requestEntity.getId().equals(userWithSameName.getId())) { throw new CommonAlredyExistException("username", "Un utilisateur avec le même login existe déjà."); } if (requestEntity.isUpdatePassword()) { actualEntity.setPwd(CommonTools.encryptPassword(requestEntity.getPwd())); } actualEntity.setDateDerniereModification(new Date()); if (utilisateurConnecte != null) { actualEntity.setUtilisateurModification(utilisateurConnecte.getUserName()); } validerMotDePasseModifier(requestEntity.isUpdatePassword(), requestEntity.getPwd(), actualEntity); checkerParticipants(requestEntity); actualEntity.setAlertDelay(requestEntity.getAlertDelay()); actualEntity.setAttemps(requestEntity.getAttemps()); actualEntity.setAttempsNumber(requestEntity.getAttempsNumber()); actualEntity.setConnected(requestEntity.isConnected()); actualEntity.setExpirationDelay(requestEntity.getExpirationDelay()); actualEntity.setFirstName(requestEntity.getFirstName()); actualEntity.setLastName(requestEntity.getLastName()); actualEntity.setLocked(requestEntity.isLocked()); actualEntity.setActive(requestEntity.isActive()); actualEntity.setRole(requestEntity.getRole()); actualEntity.setTypeFichiers(requestEntity.getTypeFichiers()); actualEntity.setParticipants(requestEntity.getParticipants()); } @Override public void beforeRemove(User entity, User utilisateurConnecte) { entity.setTypeOperation(TypeOperation.SUPPRIMER); entity.setDateSuppression(new Date()); if (utilisateurConnecte != null) { entity.setUtilisateurSuppression(utilisateurConnecte.getUserName()); } } @Override public void beforeAdd(User entity, User utilisateurConnecte) { if (entity.getUserName() != null && !entity.getUserName().isEmpty() && recuperUtilisateur(entity.getUserName()) != null) { throw new CommonAlredyExistException("userName", "Un utilisateur avec le même nom utilisateur existe déjà."); } checkerSiMotDePasseComplexe(true, entity.getPwd()); checkerParticipants(entity); entity.setPwd(CommonTools.encryptPassword(entity.getPwd())); entity.setDateCreation(new Date()); entity.setEtatOperation(EtatOperation.ATTENTE_VALIDATION); entity.setDateDerniereModificationMotDePasse(new Date()); if (utilisateurConnecte != null) { entity.setUtilisateurCreation(utilisateurConnecte.getUserName()); } } @Override public User remove(Long id, User connectedUser) { User entity = find(getEntityIdName(), id); beforeRemove(entity, connectedUser); User updatedUser = update(id, entity); messageSystemeManager.ajouter(TypeMessageSysteme.ERREUR, TypeIdMessageSysteme.SUPPRESSION_COMPTE_UTILISATEUR, "Oups ! il semblerait que votre compte utilisateur ait été supprimé, en conséquence vous allez être déconnecté.", entity); return updatedUser; } /** * Methode permettant d'effectuer des controles sur les participants (sur la * présence ou non) * * @param utilisateur */ private void checkerParticipants(User utilisateur) { /* Si non null */ if (utilisateur != null && utilisateur.getRole() != null) { /* On parcourt la liste des actions */ for (Action action : utilisateur.getRole().getActions()) { /* Si actions liées à génération des mot de passe pour l'API sont présents */ if ((action.getModule().equalsIgnoreCase(AppCommonContext.MODULE_ADMINISTRATION) && action.getPath().equalsIgnoreCase(AppCommonContext.PATH_API_TOKEN)) && (utilisateur.getParticipants() == null || utilisateur.getParticipants().isEmpty())) { /* On lève l'exception */ //throw new ApplicationValidationException(Arrays.asList("Veuillez sélectionner au moins un participant")); } } } } @Override public Class getClazz() { return UserReporting.class; } @Override public Map getParameters() { return new HashMap<>(); } @Override public List getDatas(CriteriaEntityFromView searchEntity) throws Exception { return CommonsToolsEntity.convertToUserReporting(findAll(searchEntity, Arrays.asList(), Arrays.asList())); } @Override public File printAll(ReportConfiguration reportConfiguration, User userConnected) throws Exception { return generatePdf(finalReportConfiguration(reportConfiguration), userConnected, false); } @Override public File printOne(ReportConfiguration reportConfiguration, User userConnected) throws Exception { return generatePdf(finalReportConfiguration(reportConfiguration), userConnected, true); } @Override public File exportExcelAll(ReportConfiguration reportConfiguration, User userConnected) throws Exception { return exportExcel(finalReportConfiguration(reportConfiguration), userConnected, false); } @Override public File exportExcelOne(ReportConfiguration reportConfiguration, User userConnected) throws Exception { return exportExcel(finalReportConfiguration(reportConfiguration), userConnected, true); } /** * Permet de recuperer un utilisateur via son id * * @param id * @return */ @Override public User findById(Long id) { return find(getEntityIdName(), id); } /** * Permet de checker si un mot de passe saisi est complexe * * @param motDePasse */ private void checkerSiMotDePasseComplexe(boolean siMotDePasseModifier, String motDePasse) { //Variables String erreurs = null; //Si mot de passe editer if (siMotDePasseModifier) { if (motDePasse != null && !motDePasse.isEmpty() && !motDePasse.matches("^(?=.*[0-9])(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#&()–[{}]:;',?/*~$^+=<>]).{8,20}$")) { erreurs = "Le mot de passe doit contenir :" + " \n\t - Au moins un chiffre" + " \n\t - Au moins une minuscule" + " \n\t - Au moins une majuscule" + " \n\t - Au moins un caractère special (! @ # & ( ))" + " \n\t - Au moins 8 caractères et 20 caractères maximum"; }; //Si erreurs if (erreurs != null && !erreurs.isEmpty()) { throw new CommonApplicationValidationException(erreurs); } } } /** * Permet d'effectuer certains controle après la modification du mot de * passe * * @param siMotDePasseModifier * @param nouveauMotDepasse * @param user */ private void validerMotDePasseModifier(boolean siMotDePasseModifier, String nouveauMotDepasse, User user) { //Si mot de passe modifié if (siMotDePasseModifier) { //Si mot de passe dejà utilisé checkerSiMotDePasseDejaUtilise(nouveauMotDepasse, user); //Si mot de passe complexe checkerSiMotDePasseComplexe(siMotDePasseModifier, nouveauMotDepasse); //On set la date de derniere modification user.setDateDerniereModificationMotDePasse(new Date()); } } /** * Permet de checker si un mot de passe a deja été utilsé * * @param motDePasse * @param user */ private void checkerSiMotDePasseDejaUtilise(String motDePasse, User user) { if (historiqueMotDePasseManager.siMotDePasseExiste(motDePasse, user)) { //Si mot de passe déjà utilisé throw new CommonApplicationValidationException("Ce mot de passe correspond à un mot de passe que vous avez déjà utilisé, veuillez en saisir un autre."); } else { //Sinon on enregistre historiqueMotDePasseManager.ajouter(CommonTools.encryptPassword(motDePasse), user); } } @Override public void editPassword(String username, EditPasswordDto editPasswordDto) { if (!editPasswordDto.getNewPassword().equals(editPasswordDto.getNewPasswordConfirm())) { throw new CommonApplicationValidationException("Le nouveau mot de passe et le mote de passe de confirmation ne sont pas identiques."); } User user = recuperUtilisateur(username); if (user == null) { throw new CommonApplicationValidationException("Imposssible d'effectuer l'action: utilisateur non reconnu"); } try { if (!CommonTools.validerMotDePasse(editPasswordDto.getActualPassword(), user.getPwd())) { throw new CommonApplicationValidationException("Le mot de passe actuel est incorrect"); } } catch (NoSuchAlgorithmException | InvalidKeySpecException ex) { throw new CommonApplicationValidationException("Impossible d'effectuer l'opération une erreur interne du serveur s'est produite"); } validerMotDePasseModifier(true, editPasswordDto.getNewPassword(), user); user.setPwd(CommonTools.encryptPassword(editPasswordDto.getNewPassword())); update(user.getId(), user); } @Override public List validerParametresConnexion(String username, String password) { //Variables List errors = new ArrayList<>(); User user = recuperUtilisateur(username, password); //Si null if (user == null) { //On recupère l'utilisateur via son login user = recuperUtilisateur(username); //Si non null et non administrateurs if (user != null && !(user.getRole().getAdmin() || user.getRole().getMegaAdmin() || user.getRole().getSuperAdmin())) { //Si le nombre de tentatives est depassé if (user.getAttemps() >= user.getAttempsNumber()) { //Si compte pas encore verrouillé if (!user.isLocked()) { //On verrouille le compte user.setLocked(true); } //On met à jour update(user.getId(), user); //On lève l'exeption errors.add("Suite à l'echec des " + user.getAttempsNumber() + " tentative(s) de connexions à ce compte, ce dernier a été verrouillé. " + "\n Veuillez contacter l'administrateur."); } else { //On comptabilise le nombre de tentatives user.setAttemps(user.getAttemps() + 1); //On met à jour update(user.getId(), user); //Si nbre tentatives > 0 if ((user.getAttempsNumber() - user.getAttemps()) > 0) { //On lève l'exeption errors.add("Login ou mot de passe incorrect, Il vous reste (" + ((user.getAttempsNumber() - user.getAttemps())) + ") tentative(s)"); } else { //Si compte pas encore verrouillé if (!user.isLocked()) { //On verrouille le compte user.setLocked(true); } //On met à jour update(user.getId(), user); //On lève l'exeption errors.add("Suite à l'echec des " + user.getAttempsNumber() + " tentative(s) de connexions à ce compte, ce dernier a été verrouillé. " + "\n Veuillez contacter l'administrateur."); } } } else { //On lève l'exeption errors.add("Login ou mot de passe incorrect."); } } else { //Ces controles ne concernent pas les administrateurs par defauts if (!(user.getRole().getAdmin() || user.getRole().getMegaAdmin() || user.getRole().getSuperAdmin())) { if (user.getEtatOperation() != EtatOperation.ACTIF) { //Si compte non actif //On lève l'exeption errors.add("Compte non activé.\n Veuillez contacter l'administrateur."); } else if (user.isLocked()) { //Si compte verrouillé //On lève l'exeption errors.add("Compte verrouillé.\n Veuillez contacter l'administrateur."); } //On calcule le nbre de jour restant avant expiration du mot de passe calculerNbreJoursAvantExpirationMotDePasse(user); //On verifie si le mot de passe a expiré checkerExpirationMotDePasse(user); //On reset le nombre de tentatives user.setAttemps(0); //On met à jour update(user.getId(), user); } else { //On calcule le nbre de jour restant avant expiration du mot de passe calculerNbreJoursAvantExpirationMotDePasse(user); //On verifie si le mot de passe a expiré checkerExpirationMotDePasse(user); //On met à jour update(user.getId(), user); } } return errors; } /** * Permet de determiner si la delai d'expiration mot de passe est arrivé * * @param user */ public void checkerExpirationMotDePasse(User user) { //Si mot de passe expiré if (siDelaiExpirationArrive(user)) { //On ajoute à la pile des messages système messageSystemeManager.ajouter(TypeMessageSysteme.AVERTISSEMENT, TypeIdMessageSysteme.MOT_DE_PASSE_EXPIRE, "Votre mot de passe a expiré, veuillez le modifier.", user); } } /** * Permet de determiner si la delai expiration mot de passe arrivé * * @param user */ public boolean siDelaiExpirationArrive(User user) { //Variables Date dateFuturExpirationMotDePasse = null; Date dateCourante = new Date(); //Si egal à zero (n'expire jamais) if (user.getExpirationDelay() == 0) { return false; } else { //On calcule la date d'expiration dateFuturExpirationMotDePasse = CommonTools.addDay(user.getDateDerniereModificationMotDePasse(), user.getExpirationDelay()); //On compare si la date courante est supérieur ou égale à la date d'expiration if (dateCourante.getTime() >= dateFuturExpirationMotDePasse.getTime()) { return true; } else { return false; } } } /** * Cette methode permet de calculer le nombre de jours avant expiration du * mot de passe * * @param utilisateur */ private void calculerNbreJoursAvantExpirationMotDePasse(User utilisateur) { //Variables Date dateFuturExpirationMotDePasse = null; Date dateCourante = new Date(); long difference = 0l; Integer nbreJoursRestant = 0; String message = ""; //Si egal à zero (n'expire jamais) if (utilisateur.getExpirationDelay() > 0) { //On calcule la date d'expiration dateFuturExpirationMotDePasse = CommonTools.addDay(utilisateur.getDateDerniereModificationMotDePasse(), utilisateur.getExpirationDelay()); //On compare si la date courante est inferieur ou egale à la date d'expiration if (dateCourante.getTime() < dateFuturExpirationMotDePasse.getTime()) { //On calcule la difference en milli seconde difference = dateFuturExpirationMotDePasse.getTime() - dateCourante.getTime(); //On recupere le nombre de jours restant avant expiration nbreJoursRestant = new BigDecimal(TimeUnit.DAYS.convert(difference, TimeUnit.MILLISECONDS)).intValue(); //Si le nbre jours restant est inferieur ou egal au seuil d'alerte if (nbreJoursRestant <= utilisateur.getAlertDelay()) { //Si nbre jour == 0, switch (nbreJoursRestant) { case 0: //On recupere le message message = "Votre mot de passe expire aujourd'hui, pensez à le modifier"; break; case 1: //On recupere le message message = "Votre mot de passe expire demain, pensez à le modifier"; break; default: //On recupere le message message = "Votre mot de passe expire dans (" + CommonTools.formaterChiffreAvecZeroDevant(nbreJoursRestant) + ") jour(s), \n Pensez à le modifier."; break; } //On ajoute à la pile des messages système messageSystemeManager.ajouter(TypeMessageSysteme.AVERTISSEMENT, TypeIdMessageSysteme.ALERTE_MOT_DE_PASSE_EXPIRE, message, utilisateur); } } } } @Override public List obtenirListeUtilisateursRole(Role role) { return dao.obtenirListeUtilisateursRole(role); } @Override public PaginationWithCriteriaEntityDAO paginationWithCriteriaEntityDAO() { return dao; } @Override public RestrictionsContainer construireRequete(UserSearch searchEntity, TypeOperation typeOperation) { RestrictionsContainer requeteur = RestrictionContainerBuildeUtil.construireRequete(searchEntity, UserSearch.class); requeteur.addEq("typeOperation", typeOperation); return requeteur; } }