Problèmes connus¶
Ce chapitre revient sur certains problèmes identifiés et pour lesquels il n'existe pas de solution directement intégrée à Ewt. Des axes de solution sont proposés lorsque cela est possible.
Duplications de sessions¶
Lorsqu'on duplique un onglet sur lequel on est connecté à une application Ewt, cela ouvre une nouvelle fenêtre qui partage la même session et les mêmes cookies. Le moteur n'est alors pas capable de faire la distinction entre les requêtes provenant de l'un ou l'autre des deux onglets. Le fait que deux onglets distincts (ou plus) génèrent des requêtes pour une même session Ewt peut entraîner au mieux des blocages de policies ou, au pire, des écrasements de valeurs ou des comportements imprévisibles. Il n'est donc pas souhaitable que cette situation se produise.
En réalité il n'est pas possible d'empêcher un utilisateur de dupliquer un onglet. Le fait d'ouvrir le résultat d'un traitement peut d'ailleurs être une fonctionnalité standard d'une application. Il est donc nécessaire d'avoir un mécanisme qui permette d'éviter que différents onglets ne soient liés à une même session.
Voici deux solutions qui peuvent être mises en place dans une application.
1. Identifiant d'onglet¶
Une première option consiste à lier un identifiant d'onglet à la session. L'identifiant peut être généré en JavaScript via le code suivant :
function getTabId() {
if (!window.name) {
window.name = 'tab_' + Date.now();
}
return window.name;
}
Comme la propriété window.name est propre à chaque onglet, on a la
garantie que deux onglets ne pourront pas avoir le même identifiant.
Pour transmettre l'identifiant d'onglet au moteur d'application, vous pouvez au choix:
- Utiliser un champ de formulaire nommé
EWT:TABID - Transmettre l'identifiant d'onglet via l'entête HTTP
x-ewt-tabid
Lorsqu'il reçoit un identifiant d'onglet, le moteur associe celui-ci à la session, pour autant que la session ne possède pas déjà un autre identifiant d'onglet. En cas de conflit, le moteur se charge automatiquement de cloner la session pour le nouvel onglet et d'y associer l'identifiant reçu.
2. Communication inter-onglets¶
La logique de gestion de conflit peut être implémentée au niveau de l'application elle-même. Cela implique que les onglets communiquent au moyen du service BroadcastChannel.
En effet, le service BroadcastChannel permet d'envoyer et de recevoir des messages au sein des différents onglets, des différentes fenêtres, iframe ou workers qui portent sur une même session (la portée est en réalité un peu différente de cela, mais cela correspond à notre besoin).
Une solution est donc d'utiliser cette interface pour mettre en place une
communication entre les onglets qui partagent une même session. L'idée est
d'envoyer un message invalidate via le channel lors d'un submit afin
d'indiquer à tous les autres onglets qu'ils doivent s'invalider. Chaque
onglet décidera alors du comportement à adopter (afficher un bandeau
d'avertissement à l'écran, fermer tous les dossiers ouverts, forcer un
retour à la page d'accueil au moyen d'une requête GET, etc.)
Ci-dessous, nous donnons un exemple de solution qui va dans ce sens.
Ici la méthode onMessage force un retour à la page d'accueil de
l'application au moyen de window.open. Cette action offre deux avantages:
- Elle force l'utilisateur à quitter tout dossier ouvert qui pourrait être modifié depuis un autre onglet
- Elle force la création d'une session propre à l'onglet, ce qui permet d'éviter les conflits de sessions sur les requêtes à venir.
On pourrait améliorer ce comportement par exemple en annonçant à l'utilisateur que la page va se fermer.
Erreurs liées au reverse proxy¶
Certaines erreurs peuvent apparaître lorsque l'application est déployée derrière un reverse proxy, du fait que certains éléments d'en-tête ne sont pas correctement véhiculés, notamment les cookies de session.
Cas 1 : le navigateur signale une alerte de type Mixed Content¶
Symptomes: Le problème peut s'exprimer de différentes manières.
-
le navigateur affiche le message suivant lors de l'authentification
Les informations saisies vont être transmises en clair (sans chiffrement). Elles peuvent donc éventuellement être interceptées et lues lors de leur acheminement.
Voulez-vous vraiment transmettre ces informations ? -
la trace réseau montre que certaines requêtes transitent via une URL en http
En premier lieu, il faut indiquer à Tomcat de tenir compte des en-têtes
qui véhiculent l'information qui nous manque. Pour cela, éditez le fichier
server.xml et ajoutez la valve suivante à la fin du bloc
/Server/Service/Engine/Host:
<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
proxiesHeader="x-forwarded-by"
protocolHeader="x-forwarded-proto"
portHeader="x-forwarded-port"/>
Il reste à configurer le serveur web en amont (Apache, Nginx, IIS) pour qu'il transmette les en-têtes contenant les informations que nous recherhons.
Redémarrez ensuite Tomcat et le serveur web:
Il se peut que ce dernier signale une
erreur au redémarrage, en mentionnant une erreur de syntaxe avec l'entrée
RequestHeader. Si tel est le cas, lancez la commande suivante pour
installer le module mod_header:
Si vous n'avez pas la main sur le serveur web
Si vous n'avez pas la main sur le serveur web, il nous faut alors forcer nous-même la valeur des en-têtes. Ewt intègre une classe qui permet de faire cela, mais cette solution n'est pas recommandée en production.
Ajoutez les éléments suivants dans le fichier web.xml :
<filter>
<filter-name>EwtHttpsFilterEnforcer</filter-name>
<filter-class>ch.epilogic.ewt.auth.utils.EwtHttpsFilterEnforcer</filter-class>
</filter>
<filter-mapping>
<filter-name>EwtHttpsFilterEnforcer</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
La classe ch.epilogic.ewt.auth.utils.EwtHttpsFilterEnforcer est un
filtre qui fait croire au serveur d'application que nous sommes sur un
environnement https.
Cas 2 : le cookie est perdu lors son envoi du navigateur vers le serveur¶
Il se peut que les cookies soient perdus lors du traitement de la requête par Httpd, du fait qu'il porte sur un domaine et/ou un contexte qui diffère entre l'interne et l'externe.
Éditez le fichier de configuration ssl présent dans
/etc/apache/sites-enabled.
Ajoutez les lignes suivantes:
ProxyPassReverseCookiePath /internalContext /externalContext
ProxyPassReverseCookieDomain localhost example.com
Sauvegardez les modifications et redémarrez le serveur Apache Httpd.
Message d'avertissement "Unable to get fieldset for `...`"¶
Illustrons le cas avec un exemple:
Le champ ci-dessus est un champ en lecture seule qui référence une autorisation. L'autorisation en question est liée à une fiche client, et on profite de ce lien pour afficher deux boutons sur la gauche du champ: le premier référence l'autorisation et le second référence le client.
À l'exécution, les messages d'avertissement suivants s'affichent dans le log:
L'avertissement est d'autant plus étrange que les boutons fonctionnent parfaitement et contiennent des identifiants de dossiers valides.
Le problème vient du fait que la property ne contient aucune indication de
destination. Le moteur applique donc la destination par défaut. Dans le
contexte d'un champ, il s'agit de descript-full,document. Or le moteur
n'est pas capable de résoudre les références de contexte lorsqu'il doit
générer les éléments pour la partie descript de l'arbre de sortie, car à
ce moment il n'est pas dans le contexte d'un dossier.
La solution pour éviter l'avertissement est donc de spécifier explicitement la destination en changeant la ligne 7 ainsi:
L'insertion multiple ne fonctionne pas avec $sql.insert¶
Ce problème est documenté au niveau de la méthode
$sql.insert. La solution rapide consiste à utiliser
$sql.update dans ce cas.
Le rechargement de l'application affiche des erreurs de niveau SEVERE concertant le driver Oracle¶
L'erreur suivante peut être affichée plusieurs fois lors d'un rechargement de l'instance:
SEVERE [Catalina-utility-2] org.apache.catalina.loader.WebappClassLoaderBase.checkThreadLocalMapForLeaks
The web application [ewt] created a ThreadLocal with key of type
[oracle.jdbc.driver.AutoKeyInfo$1] (value [oracle.jdbc.driver.AutoKeyInfo$1@c0e5915])
and a value of type [oracle.jdbc.driver.OracleSql] (value
[INSERT INTO ewt_sessions(sessionId) VALUES(?)]) but failed to remove it
when the web application was stopped. Threads are going to be renewed
over time to try and avoid a probable memory leak.
Cela vient du fait que le serveur d'application (Tomcat dans le cas ci-dessus) décharge le classloader associé à l'application alors que le driver Oracle a laissé un ThreadLocal non nettoyé dans un thread actif.
Pour éviter le message, une solution consiste à déplacer le driver Oracle au
niveau des dépendances du serveur d'application Tomcat lui-même,
c'est-à-dire en déplaçant le fichier jar du driver Oracle dans le dossier
lib de Tomcat. Ainsi le classloader ne sera pas détruit à chaque
redémarrage de l'instance de l'application.
Erreur 403 après authentification par OIDC ou SAML¶
L'erreur HTTP 403 signifie que l'utilisateur est authentifié, mais qu'il ne dispose pas des rôles suffisants pour utiliser l'application. Selon l'IdP utilisé, les rôles ne sont pas toujours véhiculés de la même façon. En particulier, il peut arriver que les rôles soient passés via un attribut auquel le module d'authentification ne s'attend pas.
Une analyse de la réponse du serveur est nécessaire pour savoir via quel attribut sont passés les rôles.
En cas de requête SAML, vous pouvez utiliser l'extension de navigateur SAML-Tracer pour pouvoir visionner le contenu de la requête. Cela ne sera cependant pas utile sur les assertions sont chiffrées. Dans ce cas, vous pouvez vous rabattre sur la solution suivante:
-
Dans le fichier
ewtAuthConfig.xml, ajoutez le bloc suivant: -
Dans le même fichier, ajoutez l'élément suivant à votre client (c.-à-d. dans le bloc
<client>pour lequel vous ne retrouvez pas les rôles): -
Dans l'application "MonApplication", créez le script suivant:
Redémarrez le serveur. À la prochaine connexion, le moteur devrait invoquer le script ci-dessus qui va se charger d'inscrire dans le log toutes les données relatives au profil (adaptez le log level si nécessaire). Vous devriez pouvoir y trouver l'attribut contenant les rôles.
À partir de là, vous avez deux options possibles :
Une fois le nom de l'attribut trouvé, éditez à nouveau le fichier
ewtAuthConfig.xml. Commentez ou retirez la ligne
<repository>script-file-repo-direct</repository> du client, et ajoutez
la ligne suivante (en adaptant la valeur "Role" par la valeur que vous
aurez trouvé):
Redémarrez le serveur d'application après modification.
Ewt permet de personnaliser le profil utilisateur directement depuis le
script dumpProfile.ewts. Veuillez consulter la documentation de la
méthode $auth.returnUser pour les
détails.