Commit c0731708 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

WIP bootstrap 3 => 4

parent 3f5c91a5
Pipeline #11037 passed with stage
in 29 seconds
CHANGELOG
=========
3.2.6 / 3.2.7
-----
- Ajout d'un événement avec le détail des erreurs LDAP
3.2.5
-----
- [FIX] Petite correction d'une NOTICE qui apparaissait lorsqu'on se déconnectait.
3.2.3
-----
- [FIX] Meilleure gestion d'erreur en cas de demande d'usurpation d'un compte inexistant : retour à l'accueil + message.
3.2.2
-----
- L'URL de connexion accepte désormais role=ROLE_ID pour sélectionner automatiquement ce rôle une fois authentifié.
......@@ -72,4 +85,4 @@ CHANGELOG
3.0.0 (17/09/2019)
------------------
Première version officielle sous ZF3.
\ No newline at end of file
Première version officielle sous ZF3.
......@@ -10,6 +10,7 @@ use UnicaenAuth\Service\User;
use Zend\Authentication\Adapter\Ldap as LdapAuthAdapter;
use Zend\Authentication\Exception\ExceptionInterface;
use Zend\Authentication\Result as AuthenticationResult;
use Zend\EventManager\Event;
use Zend\EventManager\EventInterface;
use Zend\EventManager\EventManager;
use Zend\EventManager\EventManagerAwareInterface;
......@@ -24,11 +25,13 @@ use ZfcUser\Authentication\Adapter\AdapterChainEvent;
class Ldap extends AbstractAdapter implements EventManagerAwareInterface
{
use ModuleOptionsAwareTrait;
const TYPE = 'ldap';
const USURPATION_USERNAMES_SEP = '=';
const LDAP_AUTHENTIFICATION_FAIL = 'authentification.ldap.fail';
/**
* @var string
*/
......@@ -88,7 +91,8 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
// NB: Dans la version 3.0.0 de zf-commons/zfc-user, cette méthode prend un EventInterface.
// Mais dans la branche 3.x, c'est un AdapterChainEvent !
// Si un jour c'est un AdapterChainEvent qui est attendu, plus besoin de faire $e->getTarget().
$event = $e->getTarget(); /* @var $event AdapterChainEvent */
$event = $e->getTarget();
/* @var $event AdapterChainEvent */
if ($this->isSatisfied()) {
try {
......@@ -103,7 +107,7 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
return true;
}
$username = $event->getRequest()->getPost()->get('identity');
$username = $event->getRequest()->getPost()->get('identity');
$credential = $event->getRequest()->getPost()->get('credential');
if (function_exists('mb_strtolower')) {
......@@ -115,7 +119,7 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
$success = $this->authenticateUsername($username, $credential);
// Failure!
if (! $success) {
if (!$success) {
$event
->setCode(AuthenticationResult::FAILURE)
->setMessages([/*'LDAP bind failed.'*/]);
......@@ -201,16 +205,33 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
}
// LDAP auth
$result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
$result = $this->getLdapAuthAdapter()->setUsername($username)->setPassword($credential)->authenticate();
// Envoi des erreurs LDAP dans un événement
if (!$result->isValid()) {
$messages = "LDAP ERROR : ";
$errorMessages = $result->getMessages();
if (count($errorMessages) > 0) {
// On ne prend que les 2 premières lignes d'erreur (les suivantes contiennent souvent
// les mots de passe de l'utilisateur, et les mot de passe dans les logs... bof bof).
for ($i = 0; $i < 2 && count($errorMessages) >= $i; $i++) {
$messages .= $errorMessages[$i] . " ";
}
}
$errorEvent = new Event(self::LDAP_AUTHENTIFICATION_FAIL, null, ['messages' => $messages]);
$this->getEventManager()->triggerEvent($errorEvent);
}
$success = $result->isValid();
// verif existence du login usurpé
if ($this->usernameUsurpe) {
// s'il nexiste pas, échec de l'authentification
if (!@$this->getLdapAuthAdapter()->getLdap()->searchEntries("(".$this->moduleOptions->getLdapUsername()."=$this->usernameUsurpe)")) {
if (!@$this->getLdapAuthAdapter()->getLdap()->searchEntries(
"(" . $this->moduleOptions->getLdapUsername() . "=$this->usernameUsurpe)"
)) {
$this->usernameUsurpe = null;
$success = false;
$success = false;
}
}
......@@ -293,10 +314,12 @@ class Ldap extends AbstractAdapter implements EventManagerAwareInterface
*/
public function setEventManager(EventManagerInterface $eventManager): self
{
$eventManager->setIdentifiers([
__NAMESPACE__,
__CLASS__,
]);
$eventManager->setIdentifiers(
[
__NAMESPACE__,
__CLASS__,
]
);
$this->eventManager = $eventManager;
return $this;
......
......@@ -2,6 +2,7 @@
namespace UnicaenAuth\Controller;
use Exception;
use UnicaenApp\Exception\RuntimeException;
use UnicaenApp\Mapper\Ldap\People as LdapPeopleMapper;
use UnicaenAuth\Entity\Db\AbstractUser;
......@@ -132,10 +133,19 @@ class UtilisateurController extends AbstractActionController
return $this->redirect()->toRoute('home');
}
$utilisateurUsurpe = $this->getUserMapper()->findByUsername($usernameUsurpe); /** @var AbstractUser $utilisateurUsurpe */
if ($utilisateurUsurpe === null) {
$this->flashMessenger()->addErrorMessage(
"La demande d'usurpation du compte '$usernameUsurpe' a échoué car aucun compte utilisateur correspondant " .
"n'a été trouvé."
);
return $this->redirect()->toRoute('home');
}
$sessionIdentity = $this->serviceUserContext->usurperIdentite($usernameUsurpe);
if ($sessionIdentity !== null) {
// cuisine spéciale si l'utilisateur courant s'est authentifié via Shibboleth
$this->usurperIdentiteShib($usernameUsurpe);
$this->usurperIdentiteShib($utilisateurUsurpe);
}
return $this->redirect()->toRoute('home');
......@@ -144,19 +154,15 @@ class UtilisateurController extends AbstractActionController
/**
* Cuisine spéciale pour l'usurpation si l'utilisateur courant s'est authentifié via Shibboleth.
*
* @param string $usernameUsurpe Ex tartempion@unicaen.fr
* @param AbstractUser $utilisateurUsurpe Utilisateur à usurper
*/
protected function usurperIdentiteShib(string $usernameUsurpe)
protected function usurperIdentiteShib(AbstractUser $utilisateurUsurpe)
{
$currentIdentityArray = $this->serviceUserContext->getIdentity();
if (isset($currentIdentityArray['shib']) && $currentIdentityArray['shib'] instanceof ShibUser) {
$fromShibUser = $currentIdentityArray['shib'];
$toUtilisateur = $this->getUserMapper()->findByUsername($usernameUsurpe); /** @var AbstractUser $toUtilisateur */
if ($toUtilisateur === null) {
throw new RuntimeException("L'utilisateur '$usernameUsurpe' n'existe pas dans la table des utilisateurs");
}
$this->shibService->activateUsurpation($fromShibUser, $toUtilisateur);
$this->shibService->activateUsurpation($fromShibUser, $utilisateurUsurpe);
}
}
......
......@@ -335,12 +335,15 @@ class UserContext extends AbstractService implements EventManagerAwareInterface
unset($this->getSessionContainer()->selectedIdentityRole);
}
$role = $this->getSelectableIdentityRoles()[$role];
if ($role instanceof AbstractRole) {
$this->saveUserLastRole($role);
}
$selectableIdentityRoles = $this->getSelectableIdentityRoles();
if (isset($selectableIdentityRoles[$role])){
$role = $selectableIdentityRoles[$role];
if ($role instanceof AbstractRole) {
$this->saveUserLastRole($role);
}
$this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);
$this->triggerUserRoleSelectedEvent(UserRoleSelectedEvent::POST_SELECTION, $role);
}
return $this;
}
......
......@@ -52,7 +52,7 @@ class UserCurrent extends UserAbstract
$selectableRoles = $this->getUserContext()->getSelectableIdentityRoles();
$role = current($selectableRoles) ?: $this->getUserContext()->getIdentityRole('user');
}
$status .= sprintf(", <small class='role-libelle'>%s</small>", !method_exists($role, '__toString') ? $role->getRoleId() : $role);
$status .= sprintf("<br/><small class='role-libelle'>%s</small>", !method_exists($role, '__toString') ? $role->getRoleId() : $role);
}
$userProfileHelper = $this->getView()->plugin('userProfile'); /* @var $userProfileHelper UserProfile */
......@@ -77,13 +77,13 @@ class UserCurrent extends UserAbstract
}
$out = <<<EOS
<a class="navbar-link"
<a class="navbar-link dropdown-toggle"
id="$id"
title="$title"
data-placement="bottom"
data-toggle="popover"
data-html="true"
data-content="$content"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-html="true"
data-bs-content="$content"
href="#">$status<span class="caret"></span></a>
EOS;
$out .= PHP_EOL;
......
......@@ -36,7 +36,7 @@ class UserProfile extends UserAbstract
*/
public function render()
{
$title = _("Profil utilisateur");
$title = _("Rôle utilisateur");
$unknown = _("Inconnu");
$none = _("Aucun");
......
......@@ -2,6 +2,7 @@
namespace UnicaenAuth\View\Helper;
use Zend\Permissions\Acl\Role\RoleInterface;
use Zend\View\Helper\HeadScript;
/**
* Aide de vue permettant à l'utilisateur de sélectionner son profil courant parmi
......@@ -79,18 +80,15 @@ class UserProfileSelect extends UserAbstract
$url = $this->getView()->url('utilisateur/default', ['action' => 'selectionner-profil']);
$redirectUrl = $this->getView()->url($this->redirectRoute ?: 'home');
$html .= <<<EOS
<script>
$(function() {
$("input.$inputClass").change(function() { submitProfile(); }).tooltip({ delay: 500, placement: 'left' });
});
function submitProfile()
{
$js = <<<EOS
$(function() {
$("body").on("change", "input.$inputClass", function() {
$("body *").css('cursor', 'wait');
$.post("$url", $(".$formClass").serializeArray(), function() { $(location).attr('href', "$redirectUrl"); });
}
</script>
});
});
EOS;
$this->view->inlineScript(HeadScript::SCRIPT, $js);
return $html;
}
......
......@@ -11,6 +11,7 @@ use Zend\Form\Element\Text;
use Zend\Form\Form;
use Zend\Form\View\Helper\Form as FormHelper;
use Zend\Form\View\Helper\FormElement;
use Zend\View\Helper\HeadScript;
use Zend\View\Renderer\PhpRenderer;
/**
......@@ -145,26 +146,30 @@ class UserUsurpationHelper extends UserAbstract
$html = '';
$html .= $formHelper->openTag($form);
$html .= "<div><strong>Usurpation d'identité :</strong></div>";
$html .= $formControlGroupHelper->__invoke($identity);
$html .= $formControlGroupHelper->__invoke($submit);
$html .= '<div class="row">' . PHP_EOL;
$html .= '<div class="col-sm-9">' . $formControlGroupHelper->__invoke($identity) . '</div>' . PHP_EOL;
$html .= '<div class="col-sm-3">' . $formControlGroupHelper->__invoke($submit) . '</div>' . PHP_EOL;
$html .= '</div>' . PHP_EOL;
$html .= $formHelper->closeTag();
$formId = $form->getAttribute('id');
$html .= <<<EOS
<script>
var form = $("#$formId").submit(function() {
$("body *").css('cursor', 'wait');
});
var input = form.find(".user-usurpation-input").on('input', function() {
updateUsurpationSubmit();
});
function updateUsurpationSubmit() {
form.find(".user-usurpation-submit").prop("disabled", input.val().length === 0);
}
updateUsurpationSubmit();
</script>
$js = <<<EOS
$(function() {
$("body")
.on("input", ".user-usurpation-input", function() {
const input = $(this);
const submit = $(".user-usurpation-submit");
input.val().length > 0 ?
submit.prop("disabled", false) :
submit.prop("disabled", true);
})
.on("submit", "#$formId", function() {
$("body *").css('cursor', 'wait');
});
});
EOS;
$this->view->inlineScript(HeadScript::SCRIPT, $js);
return $html;
}
......@@ -209,6 +214,7 @@ EOS;
$submit = new Submit('submit');
$submit->setValue("Usurper");
$submit->setAttributes([
'disabled' => true,
'class' => 'user-usurpation-submit btn btn-danger',
]);
......
......@@ -28,10 +28,10 @@ use Zend\Form\Form;
<?php if ($messages = $this->flashMessenger('zfcuser-login-form')): ?>
<?php foreach ($messages as $message): ?>
<div class="messenger alert alert-danger ">
<button type="button" class="close" title="Fermer cette alerte" data-dismiss="alert">×</button>
<span class="glyphicon glyphicon-warning-sign"></span>
<div class="messenger alert alert-danger alert-dismissible ">
<span class="icon icon-avertissement"></span>
<?php echo $message ?> <br>
<button type="button" class="btn-close" title="Fermer cette alerte" data-bs-dismiss="alert"></button>
</div>
<?php endforeach ?>
<?php endif ?>
......
<a class="navbar-link"
id="user-current-info"
title="Auth user"
data-placement="bottom"
data-toggle="popover"
data-content="User Profile Helper MarkupUser Info Helper Markup"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-content="User Profile Helper MarkupUser Info Helper Markup"
href="#">User Status Helper Markup</a>
<a class="navbar-link"
id="user-current-info"
title="Utilisateur connecté à l'application"
data-placement="bottom"
data-toggle="popover"
data-content="User Profile Helper MarkupUser Info Helper Markup"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-content="User Profile Helper MarkupUser Info Helper Markup"
href="#">User Status Helper Markup</a>
<a class="navbar-link"
id="user-current-info"
title="Auth user"
data-placement="bottom"
data-toggle="popover"
data-content="None"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-content="None"
href="#">User Status Helper Markup</a>
<a class="navbar-link"
id="user-current-info"
title="Utilisateur connecté à l'application"
data-placement="bottom"
data-toggle="popover"
data-content="Aucun"
data-bs-placement="bottom"
data-bs-toggle="popover"
data-bs-content="Aucun"
href="#">User Status Helper Markup</a>
......@@ -19,7 +19,7 @@ use Zend\Form\Form;
$form->prepare();
$form->setAttributes([
'class' => 'form-horizontal',
//'class' => 'form-horizontal', // .form-horizontal n'existe plus dans boostrap 4
'role' => 'form',
]);
......@@ -45,9 +45,9 @@ $activeHelper = null;
$activeClass = '';
}
?>
<li role="presentation" class="<?php echo $activeClass ?>">
<li role="presentation" class="nav-item">
<?php $query = $redirect ? ['redirect' => $redirect] : [] ?>
<a href="<?php echo $this->url('zfcuser/login', ['type' => $key], ['query' => $query]) ?>"><?php echo $helper->getTitle() ?></a>
<a class="nav-link <?php echo $activeClass ?>" href="<?php echo $this->url('zfcuser/login', ['type' => $key], ['query' => $query]) ?>"><?php echo $helper->getTitle() ?></a>
</li>
<?php endforeach ?>
</ul>
......
......@@ -31,8 +31,10 @@ $this->headTitle("Connexion") ?>
<!-- Création d'un compte local (si autorisée) -->
<?php if ($enableRegistration) : ?>
<div id="div-connexion" class="panel panel-primary">
<div id="div-connexion" class="card">
<div class="card-body">
<?php echo $this->translate("Not registered?"); ?> <a href="<?php echo $this->url('zfcuser/register') . ($this->redirect ? '?redirect=' . $this->redirect : '') ?>"><?php echo $this->translate("Sign up!"); ?></a>
</div>
</div>
<?php endif; ?>
......
......@@ -30,7 +30,7 @@ use Zend\Form\Form;
echo $this->formInput($email);
echo $this->formElementErrors($email, ['class' => 'text-danger']);
?>
<span class="help-block">Un lien à cliquer vous sera envoyé à cette adresse électronique.</span>
<span class="form-text">Un lien à cliquer vous sera envoyé à cette adresse électronique.</span>
</p>
<?php echo $this->formInput($form->get('csrf')); ?>
......
......@@ -14,7 +14,7 @@ $canEdit = $this->isAllowed(Privileges::getResourceId(Privileges::DROIT_PRIVILEG
<a href="javascript:void(0)" data-action="refuser"
title="Privilège '<?php echo $privilege->getCategorie() ?> > '<?php echo $privilege ?>' accordé au rôle '<?php echo $role ?>'. Cliquez pour le retirer.">
<?php endif; ?>
<span class="glyphicon glyphicon-ok text-success"></span>
<span class="icon iconly icon-oui text-success"></span>
<?php if ($canEdit): ?>
</a>
<?php endif; ?>
......@@ -25,7 +25,7 @@ $canEdit = $this->isAllowed(Privileges::getResourceId(Privileges::DROIT_PRIVILEG
<a href="javascript:void(0)" data-action="accorder"
title="Privilège '<?php echo $privilege->getCategorie() ?> > <?php echo $privilege ?>' refusé au rôle '<?php echo $role ?>'. Cliquez pour l'accorder.">
<?php endif; ?>
<span class="glyphicon glyphicon-remove text-danger refuse"></span>
<span class="icon iconly icon-non text-danger refuse"></span>
<?php if ($canEdit): ?>
</a>
<?php endif; ?>
......
......@@ -6,7 +6,7 @@
?>
<h1 class="page-header">Gestion des privilèges</h1>
<table class="droits-tbl table table-hover table-bordered table-condensed table-extra-condensed table-header-rotated" data-modifier-url="<?php echo $this->url('droits/privileges/modifier'); ?>">
<table class="droits-tbl table table-hover table-bordered table-sm table-extra-condensed table-header-rotated" data-modifier-url="<?php echo $this->url('droits/privileges/modifier'); ?>">
<thead>
<tr>
<th class="separator"></th>
......
......@@ -9,7 +9,7 @@ $canEdit = $this->isAllowed('privilege/'.Privileges::DROIT_ROLE_EDITION);
$ajoutUrl = $this->url( 'droits/roles/edition' );
?>
<table class="table table-condensed table-bordered">
<table class="table table-sm table-bordered">
<tr>
<th>Nom</th>
<th>Parent</th>
......@@ -28,8 +28,8 @@ $ajoutUrl = $this->url( 'droits/roles/edition' );
<td><?php echo $role->getAccessibleExterieur() ? 'Oui' : 'Non'; ?></td>
<?php if ($canEdit): ?>
<td style="width:1%;white-space: nowrap;text-align: center">
<a href="<?php echo $editionUrl; ?>" class="ajax-modal" data-event="role-edition"><span class="glyphicon glyphicon-edit"></span></a>
<a href="<?php echo $suppressionUrl; ?>" class="ajax-modal" data-event="role-suppression"><span class="glyphicon glyphicon-remove"></span></a>
<a href="<?php echo $editionUrl; ?>" class="ajax-modal" data-event="role-edition"><span class="icon iconly icon-modifier"></span></a>
<a href="<?php echo $suppressionUrl; ?>" class="ajax-modal" data-event="role-suppression"><span class="icon iconly icon-supprimer"></span></a>
</td>
<?php endif; ?>
</tr>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment