SMS-U version 2

AngularJS, Web widget, REST/JSON

Pascal.Rigaux @ univ-paris1.fr

Plan

  • Présentation
  • Single Page Application
  • AngularJS
  • Web widget
  • Authentification
  • Problèmes rencontrés

Présentation

  • service d'envoi de SMS
  • développé dans le cadre de l'UNPIdF avec un financement de la Mairie de Paris
  • développement initial réalisé par un prestataire

Fonctionnalités

  • envoi à des groupes
  • gestion de quotas
  • gestion des modérateurs
  • gestion des accusés de réception (l'envoi de SMS est asynchrone)

Présentation

SMS-U à Paris 1

  • Notre LDAP connait le numéro de portable de :
    • 80% des étudiants
    • 33% du personnel
  • Personnes ayant autorisé SMS-U (opt-in)
    • 50% des étudiants
    • 20% du personnel

Présentation

Utilisations à Paris1 en 2013/2014

En un an, 18000 SMS envoyés ➡ 1000 € (0.05€/sms)

  • Principaux consommateurs :
    • 8500 SMS : pédagogique et administratif
      (dont 50% service des sports, 30% UFR 12)
    • 8000 SMS : ré-initialisation de mot de passe
  • Nouveautés cette année :
    • rendez-vous médicaux et administratifs
    • alertes climatisation

Présentation

Migration technologique

ant maven + ant
JSF AngularJS
SOAP REST/JSON
desktop responsive web design
servlet / portlet servlet / web widget
groupes PAGS groupes LDAP / wsgroups

SMS-U v1

SMS-U v2

Pensé pour mobile

CSS Bootstrap 3.1

Single Page Application

Tout est fait en Ajax !

L'application mono-page la plus connue : Gmail

Petite démonstration avec SMS-U v2...

Pour accéder à SMS-U, authentification classique

On clique sur « Envoi SMS »...

Remarquez l'URL

On clique sur « Envoyer »...

Remarquez l'URL
(permet le lien en profondeur)

Un autre envoi

Au moment d'envoyer, la session est expirée...

On clique sur « Envoyer »...

On clique pour se logger à nouveau

Un nouvel onglet est ouvert !

window.open + postMessage

... le message a été envoyé !

L'expiration n'a pas été un problème :)

Pendant le redémarrage du serveur ?

L'utilisateur est prévenu...

Quand le serveur est démarré
l'application reprend là où elle en était

Comme l'application démarre assez vite, ce redémarrage passera souvent inaperçu

re-log transparent sur CAS avec JSONP

Single Page Application

  • toute la navigation est faite en Ajax
  • toutes les actions sont faites en Ajax :
    ➡ on s'abstrait des contraintes des <form> HTML
    ➡ les données client->serveur peuvent être complexes
  • templates manipulés dans le navigateur ➡ cache
  • routage avec URLs ...#/send
    (NB : HTML5 permet de faire plus transparent avec pushState)
  • les données de navigation sont conservées en mémoire dans le navigateur
  • la session java ne stocke que le login ! re-log transparent
  • debug facile dans le navigateur
⚠ programmation asynchrone !

AngularJS

fantastique framework javascript

  • MVC
  • liaison bidirectionnelle des données comme dans JSF
    ➡ pas de manipulation du DOM, sauf dans les directives
  • injection de dépendances comme dans Spring
  • documentation, exemples éditables (jsfiddle, plunk)
  • sécurité (avec porte de sortie : Strict Contextual Escaping), routage, validateurs de formulaires, framework de tests
  • intégration en cours dans les navigateurs (web components : object.observe, templates)

Démonstrateur de l'interface utilisateur (purement dans le navigateur avec mock web-service)

Je vous invite à aller tester !

Tests d'interface pour vérifier automatiquement la compatibilité dans différents navigateurs
NB: Protractor replaces deprecated AngularJS Scenario Runner

AngularJS vs JSF

inconvénients d'AngularJS

  • le code serveur doit être plus fiable, le spoofing des paramètres d'entrée étant facile
  • validateurs souvent dupliqués côté client
  • rôles vérifiés côté client et côté serveur

avantages d'AngularJS

  • réactivité de l'interface
  • facile, léger
  • bonne intégration avec le javascript :)
  • simple de faire des composants UI réutilisables (les "directives")

Web widget

Définition

Widget intégrable dans une page web :
  • ne maîtrise pas l'url de la page
  • peut utiliser un web service

Web widget

Utilisation dans uPortal

Il faut autoriser le portail à utiliser le web service SMS-U :

# dans config.properties:
portal.urls=http://up4-unpidf.univ-paris1.fr

Multiples possibilités d'intégration : CMS, WebProxy, JSR 168.

Pour uPortal 4, créer un canal « Advanced CMS » et mettre :


<script src="https://sms.univ-paris1.fr/WebWidget.js">

Voilà le résultat.
Ça ressemble à une portlet java !

Mais en fait, cela fait des requêtes cross-domain directement vers le web service https://sms.univ-paris1.fr/rest

Web widget vs Portlet

Web widgetPortlet
toute techno serveurseulement JVM
même serveur ou ailleursmême tomcat/java
gère authentification & sessiondélègue authentification & session
gère son autorisationpeut déléguer l'autorisation
urls #/send ➡ attention aux conflits si plusieurs SPA dans la page urls remapped pour passer par uPortal (qui fait l'agrégation html) (si plusieurs portlets dans la page, l'url contient les paramètres pour une portlet, les autres portlets utilisent les paramètres enregistrés en session)

Web widget vs Portlet

avantages du web widget

  • pas lié à un seul portail
    ➡ intégrable dans plusieurs portails
  • pas lié à un seul tomcat
    ➡ décentralisation de la maintenance, gestion, charge
  • navigation Ajax
    ➡ plus réactif, plus rapide sur mobile

inconvénients du web widget

  • authentification délicate

Authentification

Pour authentifier un web service depuis le navigateur :

possibilitécontraintes
classique maitriser l'url de la page
window.open + postMessage clic utilisateur
JSONPauth préalable, third party cookies, pas shibboleth
iframe cachéeauth préalable, third party cookies

Authentification

Shibboleth

La fédération Éducation-Recherche utilise le binding « HTTP Post ». Cela rend difficile l'authentification :

  • JSONP : impossible
  • iframe cachée : possible mais impossible de savoir si l'authentification a échoué ou est en cours

Solution :

  • tester un login automatique dans une iframe cachée
  • tout en proposant un login explicite avec window.open

NB : l'utilisation du binding « HTTP Artifact » rendrait le mécanisme similaire à CAS. Cela éviterait aussi les syndromes « page blanche » et « action "page précédente" impossible »

Authentification

Web widget sur site externe

Safari refuse les cookies des sites non visités. Cela concerne uniquement les sites externes.

Un web widget peut contourner le problème en gardant l'id de session dans sessionStorage ou en mémoire.

  • Java CAS Client : facile ➡ fait dans SMS-U (redirectAfterValidation + jsessionid dans l'URL)
  • phpCAS : facile
    (setNoClearTicketsFromUrl + sessionId en HTTP header)
  • Shibboleth SP : impossible, cookies obligatoires
  • SimpleSAMLphp, OpenSAML... : à tester

Problèmes rencontrés

Dette technique dans le code java existant

  • requêtes SQL construite à la main, sans escaping !
  • champs base de données limités à des strings très petites
  • différences entre create_tables.sql et *.hbm.xml
  • param hibernate MysqlInnodb plutôt Mysql5Innodb

  • duplication de code entre les sous-projets (DAO POJOs, *.hbm.xml, WS exceptions, WS beans)
  • librairies obsolètes (commons-httpclient, xfire)

Problèmes rencontrés

Java

  • maven
    • peu de gestion de conflits entre jars
      • xercesimpl vs xml-apis
      • conflicting versions (jackson-*, spring-*...)
      • opensaml obsolete deps
    • lent en ligne de commande
    • complexe comparé à ant
  • manque d'outils pour la gestion des css/js
  • tentative de rester à hibernate, en remplaçant la gestion des sessions hibernate esup-commons par OpenSessionInView ➡ échec ➡ autocommit=true

Problèmes rencontrés

outils pour la gestion des css/js

Javanode.js
concaténationyuicompressorgrunt-concat
minificationyuicompressorgrunt-usemin
vérification de codejshint-maven-plugin (lent)grunt-contrib-jshint
cache busterjasig resource-server (wro4j namingStrategy?) grunt-rev
download libswebjarsbower
custom jquery?grunt-jquery-builder
angular templates?grunt-angular-templates

NB : les webjars ne fournissent pas de liste ordonnée pour concaténation, par contre possibilité d'utiliser require.js

Problèmes rencontrés

Java

  • jackson est bien, mais plus compliqué qu'en PHP ou node.js
  • spring-ldap : faire une requête spécifique à l'attribut "members" pas possible (solution utilisée : bean spécifique pour accéder à "members")
  • eclipse trouve pas les sources pour le debug (solution utilisée : remote debugging)
  • JAX-RS : si utilisé pour proposer du JSON ou du XML, nécessite Accept-Content-Type rendant l'url difficile à tester dans le navigateur
  • jetty servlet3 : lenteur démarrage si classpath scanning (pb disparu !?)
  • UI beans avec setters/getters ralentissent la ré-architecturation
  • interfaces entre controller et business ralentissent la ré-architecturation

Problèmes rencontrés

AngularJS

  • conflit avec le routage jquery-mobile dans uPortal 4 (solution)
  • les « directives » sont difficiles à manipuler en dehors des cas documentés
  • prévenir les clics doublés pendant l'attente
  • danger du ng-model si pas de "."

Conclusion

  • la version 2 de SMS-U est plus réactive
  • 90% code java DAO/business inchangé
  • AngularJS très bien

Questions ?