getOptions()->getSaveLdapUserInDatabase()) { return false; } switch (true) { case $userData instanceof People: $username = $userData->getData($this->getOptions()->getLdapUsername()); $email = $userData->getMail(); $password = AbstractUser::PASSWORD_LDAP; $state = in_array('deactivated', ldap_explode_dn($userData->getDn(), 1)) ? 0 : 1; break; case $userData instanceof ShibUser: $username = $userData->getUsername(); $email = $userData->getEmail(); $password = AbstractUser::PASSWORD_SHIB; $state = 1; break; default: throw new RuntimeException("A implémenter!!"); break; } if (!$username) { return false; } if (is_int($username)) { // c'est un id : cela signifie que l'utilisateur existe déjà dans la bdd (et pas dans le LDAP), rien à faire return true; } if (!is_string($username)) { throw new RuntimeException("Identité rencontrée inattendue."); } $mapper = $this->getUserMapper(); /** @var UserInterface $entity */ $entity = $mapper->findByUsername($username); if (!$entity) { $entityClass = $this->getZfcUserOptions()->getUserEntityClass(); $entity = new $entityClass; $entity->setUsername($username); $method = 'insert'; } else { $method = 'update'; } $entity->setEmail($email); $entity->setDisplayName($userData->getDisplayName()); $entity->setPassword($password); $entity->setState($state); // pre-persist $event = new UserAuthenticatedEvent(UserAuthenticatedEvent::PRE_PERSIST); $this->triggerEvent($event, $entity, $userData); // persist $mapper->$method($entity); // post-persist $event = new UserAuthenticatedEvent(UserAuthenticatedEvent::POST_PERSIST); $this->triggerEvent($event, $entity, $userData); return true; } /** * @param UserAuthenticatedEvent $event * @param UserInterface $entity * @param People|ShibUser $userData */ private function triggerEvent(UserAuthenticatedEvent $event, $entity, $userData) { $event->setTarget($this); $event->setDbUser($entity); if ($userData instanceof People) { $event->setLdapUser($userData); } elseif ($userData instanceof ShibUser) { $event->setShibUser($userData); } $this->getEventManager()->trigger($event); } /** * @return UserMapper */ public function getUserMapper() { if ($this->userMapper === null) { $this->userMapper = $this->getServiceLocator()->get('zfcuser_user_mapper'); } return $this->userMapper; } /** * Retrieve the event manager * * Lazy-loads an EventManager instance if none registered. * * @return EventManagerInterface */ public function getEventManager() { return $this->eventManager; } /** * Inject an EventManager instance * * @param EventManagerInterface $eventManager * @return self */ public function setEventManager(EventManagerInterface $eventManager) { $eventManager->setIdentifiers([ __CLASS__, get_called_class(), ]); $this->eventManager = $eventManager; return $this; } /** * @param ModuleOptions $options * @return self */ public function setOptions(ModuleOptions $options) { $this->options = $options; return $this; } /** * @return ModuleOptions */ public function getOptions() { if (!$this->options instanceof ModuleOptions) { $this->setOptions($this->getServiceLocator()->get('unicaen-auth_module_options')); } return $this->options; } /** * @param ZfcUserModuleOptions $options * @return self */ public function setZfcUserOptions(ZfcUserModuleOptions $options) { $this->zfcUserOptions = $options; return $this; } /** * @return ZfcUserModuleOptions */ public function getZfcUserOptions() { if (!$this->zfcUserOptions instanceof ZfcUserModuleOptions) { $this->setZfcUserOptions($this->getServiceLocator()->get('zfcuser_module_options')); } return $this->zfcUserOptions; } const PASSWORD_RESET_TOKEN_SEP = '-'; const PASSWORD_RESET_TOKEN_DATE_FORMAT = 'YmdHis'; /** * Construit le formulaire de saisie de l'adresse électronique à laquelle envoyer le lien de * changement de mot de passe. * * @return Form */ public function createResetPasswordEmailForm() { $form = new Form(); $form->add((new Text('email'))->setLabel("Adresse électronique :")); $form->add((new Csrf('csrf'))); $form->add((new Submit('submit'))->setLabel("Envoyer le lien")); $emailInput = new Input('email'); $emailInput->setRequired(true); $emailInput->getValidatorChain()->attach(new EmailAddress()); $form->getInputFilter()->add($emailInput); return $form; } /** * Construit le formulaire de saisie d'un nouveau mot de passe. * * @return Form */ public function createPasswordChangeForm() { $form = new Form(); $form->add((new Password('password'))->setLabel("Nouveau mot de passe :")); $form->add((new Password('passwordbis'))->setLabel("Confirmation du nouveau mot de passe :")); $form->add((new Csrf('csrf'))); $form->add((new Submit('submit'))->setLabel("Enregistrer")); $form->getInputFilter()->add((new Input('password'))->setRequired(true)); $passwordbisInput = (new Input('passwordbis'))->setRequired(true); $passwordbisInput->getValidatorChain()->attach(new Identical('password')); $form->getInputFilter()->add($passwordbisInput); return $form; } /** * Génère puis enregistre le token permettant d'autoriser un utilisateur à changer son mot de passe. * * @param AbstractUser $user Utilisateur concerné * @return string|null Token généré */ public function updateUserPasswordResetToken(AbstractUser $user) { // Génération du token. $token = $this->generatePasswordResetToken(); // Enregistrement du token dans la table des utilisateurs $user->setPasswordResetToken($token); $this->getUserMapper()->update($user); return $token; } /** * @param AbstractUser $user */ public function clearUserPasswordResetToken(AbstractUser $user) { $user->setPasswordResetToken(null); $this->getUserMapper()->update($user); } /** * @param AbstractUser $user * @param string $password */ public function updateUserPassword(AbstractUser $user, $password) { $bcrypt = new Bcrypt(); $bcrypt->setCost($this->getZfcUserOptions()->getPasswordCost()); $password = $bcrypt->create($password); $user->setPasswordResetToken(null); $user->setPassword($password); $this->getUserMapper()->update($user); } /** * Génération d'un token pour la demande de renouvellement de mot de passe. * * @return string */ public function generatePasswordResetToken() { try { $uuid = Uuid::uuid4(); } catch (\Exception $e) { throw new RuntimeException("Erreur rencontrée lors de la génération du UUID.", null, $e); } // NB: la date de fin de vie du token est concaténée à la fin. $token = $uuid->toString() . self::PASSWORD_RESET_TOKEN_SEP . date('YmdHis', time() + 3600 * 24); // durée de vie = 24h return $token; } /** * Génération du motif permettant de rechercher un token dans la table des utilisateurs. * * Rappel: la date de génération est concaténée à la fin. * * @param string $tokenUnderTest Le token recherché * @return string */ public function generatePasswordResetTokenSearchPattern($tokenUnderTest) { return $tokenUnderTest . self::PASSWORD_RESET_TOKEN_SEP . '%'; } /** * Extrait la date de fin de vie d'un token. * * @param string $token * @return DateTime */ public function extractDateFromResetPasswordToken($token) { $ts = ltrim(strrchr($token, $sep = self::PASSWORD_RESET_TOKEN_SEP), $sep); $date = DateTime::createFromFormat(self::PASSWORD_RESET_TOKEN_DATE_FORMAT, $ts); return $date; } }