Accueil > OpenID Connect OAuth Server par DnC > Développer > Implémentation du monitoring avec Javascript : exemples pour SPIP et (...)

Implémentation du monitoring avec Javascript : exemples pour SPIP et WordPress

Implémentation du monitoring dans le plugin OpenID Connect client pour SPIP

Le site oa.dnc.global utilise ce plugin (il est client OIDC, le serpent se mord la queue !). Vous pouvez donc voir une étiquette en haut à gauche de la fenêtre qui traduit l’état du jeton d’accès lié à la connexion courante :

icône Signification
La connexion de l’utilisateur final n’est pas établie avec le serveur OIDC. Notez que l’utilisateur peut s’être connecté à l’application à l’aide de la méthode de connexion classique de SPIP.
L’utilisateur final et l’application sont connectés par OIDC.
Erreur générale, traduit malheureusement de multiples situations :
- perte de communication Internet,
- défaut de configuration du plugin,
- défaut d’inscription de l’application cliente sur le serveur OAuthSD,
- inscription de l’application sur un autre serveur, non compatible OAuthSD,
- login inconnu du serveur OAuthSD (l’utilisateur final n’est pas inscrit sur ce serveur),
- etc.
Le message peut éventuellement être plus explicite : "authentication error", ...

Le Monitoring permet également de manager la session OIDC et notamment d’effectuer la déconnexion globale (SLO).
En cliquant sur l’icône, des popups apparaissent selon l’état de connexion.

Exemple du code Javascript (avec jQuery) utilisé pour SPIP. Le plugin insère ce code en pied de chaque page.

[SPIP]

  1. /**
  2. * Plugin OpenID Connect client pour SPIP
  3. * OIDC Client Monitoring
  4. * Interroge le contrôleur OIDC Authorize avec prompt=none pour afficher l'état de connexion.
  5. * Voir également action_logout() dans oidcclient_options.php.
  6. * Auteur : B.Degoy DnC
  7. * Copyright (c) 2019 B.Degoy
  8. * Licence GPL v3.0
  9. */
  10.  
  11.     // OIDC Client Monitoring
  12.  
  13.     <?php
  14.     include_spip('inc/oidcclient_configuration'); ?>
  15.  
  16.     $(document).ready(function() {
  17.  
  18.         // Ajouter l'étiquette si elle n'existe pas
  19.         if($('#oidc').length === 0){
  20.             $('<div id="oidc">&nbsp;OIDC&nbsp;</div>   ')
  21.             .appendTo('nav')
  22.             .css('position','absolute')
  23.             .css('top','12px')
  24.             .css('left','3px')
  25.             .css('color','white')
  26.             .css('padding','3px');    
  27.         }
  28.  
  29.         var login = "<?php echo @$GLOBALS['visiteur_session']['login']; ?>";
  30.         var state = "<?php echo @$GLOBALS['visiteur_session']['state']; ?>";
  31.  
  32.         if ( login !== "" ) {
  33.             // Si on est logé localement, surveiller qu'on l'est également sur OIDC
  34.             setInterval(function(){
  35.                 $.ajax({
  36.                     type : "get",
  37.                     url : "<?php echo OIDC_AUTHORIZATION_ENDPOINT; ?>",
  38.                     data : { 'response_type' : 'code',
  39.                         'client_id' : "<?php echo OIDC_CLIENT_ID; ?>",
  40.                         'user_id' : login,
  41.                         'state' : state,
  42.                         'scope' : 'openid',
  43.                         'prompt' : 'none',
  44.                     },
  45.                     statusCode : {
  46.                         401 : function(){
  47.                             // Non authentifié sur OIDC, déconnecter localement
  48.                             var url_logout_public = "<?php echo '?action=logout&logout=local&url=' . $GLOBALS['REQUEST_URI']; ?>";
  49.                             window.location.replace(url_logout_public);
  50.                         },
  51.                         200 : function (){
  52.                             // Signaler la connexion
  53.                             $('#oidc').css('background-color', '#8f8');
  54.                             $('#oidc').text(' OIDC ');
  55.                         },
  56.  
  57.                     },
  58.                     error : function(obj,textStatus,errorThrown){
  59.                         // Signaler qu'on ne sait pas
  60.                         $('#oidc').css('background-color', 'red');
  61.                         $('#oidc').text(textStatus + ' ' + errorThrown);
  62.                     }
  63.                 });    
  64.             }, 2000);
  65.  
  66.         } else {
  67.             // Signaler la déconnexion
  68.             $('#oidc').css('background-color', 'orange');
  69.             $('#oidc').text(' OIDC ');
  70.         }
  71.  
  72.     });

Télécharger

Implémentation du monitoring dans une extension Wordpress

 Le plugin est disponible sur Github.

Le code Javascript est inséré dans un hook appelé par la fonction bootstrap() de l’extension :
[PHP]

  1. /**
  2.     * OAuthSD project https://oa.dnc.global
  3.     * OAuthSD OIDC plugin for WordPress
  4.     * Insert monitoring code in footer
  5.     * dnc1
  6.     * Author : bdegoy DnC https://degoy.com
  7.     * copyright (c) 2019 B.Degoy DnC
  8.     * Licence GPL v3.0
  9.     */
  10.  
  11.     function insert_monitoring() {
  12.      
  13.         // Enqueue some jQuery UIs
  14.         wp_enqueue_script('jquery-ui-dialog'); // from WP core
  15.         // get registered script object for jquery-ui
  16.         global $wp_scripts;
  17.         $ui = $wp_scripts->query('jquery-ui-core');
  18.         // load the Smoothness theme from Google CDN  
  19.         $protocol = is_ssl() ? 'https' : 'http';
  20.         $url = "$protocol://ajax.googleapis.com/ajax/libs/jqueryui/{$ui->ver}/themes/smoothness/jquery-ui.min.css";
  21.         wp_enqueue_style('jquery-ui-smoothness', $url, false, null);
  22.            
  23.         // OIDC Client Monitoring
  24.         $thisuri = $_SERVER['REQUEST_URI'];
  25.         $absolutepath_this_plugin = plugin_dir_path( __FILE__ );
  26.         $url_this_plugin = plugins_url('', dirname(__FILE__) ) . "/openid-connect-generic";
  27.         $state = md5(wp_get_session_token());
  28.        
  29.         // Server URLs
  30.         $settings = $this->settings;
  31.         $url_endpoint_login = $settings->endpoint_login;
  32.         $url_endpoint_token = $settings->endpoint_token;
  33.         $url_endpoint_userinfo = $settings->endpoint_userinfo;
  34.         $url_endpoint_logout = $settings->endpoint_end_session;
  35.         $parts = parse_url($url_endpoint_login);
  36.         $url_server = $parts['scheme'] . '://' . $parts['host'];
  37.        
  38.         // OIDC user
  39.         $clientID = $settings->client_id;
  40.         // $userID = ???
  41.        
  42.         // WP user
  43.         $user = get_user_by('id', get_current_user_id());
  44.         $login = $user->user_login;
  45.         $nom_auteur =$user->display_name;
  46.        
  47.         // for info popup
  48.         $infos =
  49.         '<br/>' . __('oidcclient:serveur_url','openid-connect-generic') . ' : <a href="' . $url_server . '">' . $url_server . '</a>' .
  50.         '<br/>' . __('oidcclient:client_id','openid-connect-generic') . ' : ' . $clientID .
  51.         '<br/>' . __('oidcclient:login_wp','openid-connect-generic') . ' : ' . $login .
  52.         //'<br/>' . __('oidcclient:login_oidc_court','openid-connect-generic') . ' : ' .  $userID .
  53.         '<br/>' . __('oidcclient:nom_auteur','openid-connect-generic') . ' : ' .  $nom_auteur;
  54.        
  55.         // labels and messages
  56.         $msg_session_connected_no = __('oidcclient:session_connected_no','openid-connect-generic');
  57.         $msg_session_connected_yes = __('oidcclient:session_connected_yes','openid-connect-generic');
  58.         $msg_session_connected_error = __('oidcclient:session_connected_error','openid-connect-generic');
  59.         $msg_session_open = __('oidcclient:session_open','openid-connect-generic');
  60.         $msg_session_extend = __('oidcclient:session_extend','openid-connect-generic');
  61.         $msg_session_close = __('oidcclient:session_close','openid-connect-generic');
  62.         $msg_session_expires = __('oidcclient:session_expires','openid-connect-generic');
  63.         $lbl_yes = __('oidcclient:item_yes','openid-connect-generic');
  64.         $lbl_no = __('oidcclient:item_no','openid-connect-generic');
  65.         $lbl_t_session_restant = __('oidcclient:t_session_restant','openid-connect-generic');
  66.         $lbl_delai_reponse = __('oidcclient:delai_reponse','openid-connect-generic');
  67.         $lbl_infos_titre = __('oidcclient:lbl_infos_titre','openid-connect-generic');
  68.        
  69.         // link to OIDC login                                                                                        
  70.         $link_login = $this->client_wrapper->get_authentication_url();
  71.        
  72.         // link to logout page
  73.         $url_logout = esc_url($url_this_plugin . "/oidc_logout.php?url=" . $_SERVER['REQUEST_URI']);
  74.    
  75.         echo <<<JSCODE
  76.            
  77. <script type="text/javascript">
  78.    
  79. (function($) {
  80.  
  81.     var login = "$login";
  82.     var timeleft = 0;
  83.     var connected = 0;
  84.     var connectionMsg = '';
  85.     var interval = null;
  86.     var pollperiod = 60000;
  87.     var tagappendto = '#content';
  88.     var tagtop = '120px';
  89.     var tagleft = '16px';
  90.     var responseDelay = 'Unk';
  91.  
  92.     $(document).on('ready',function(){
  93.  
  94.         // Add OIDC labels
  95.         if($('#oidc').length === 0){
  96.             $('<div id="oidc"><span id="oidctag">&nbsp;OIDC&nbsp;</span><span id="oidcinfo">&nbsp;?&nbsp;</span></div>')
  97.             .appendTo(tagappendto);
  98.             //
  99.             $('#oidc')
  100.             .css('position','absolute')
  101.             .css('top',tagtop)
  102.             .css('left',tagleft);
  103.             //
  104.             $('#oidctag')
  105.             .css('color','white')
  106.             .css('padding','3px')
  107.             .css('z-index','10000')
  108.             .on('click', function(){
  109.                 switch (connected) {
  110.                     case 0 :
  111.                         connectionMsg = "$msg_session_connected_no";
  112.                         SessionOpenDialog(connectionMsg);
  113.                         break;
  114.                     case 1 :
  115.                         connectionMsg = "$msg_session_connected_yes";
  116.                         SessionCloseDialog(connectionMsg);
  117.                         break;
  118.                     default :
  119.                     case -1 :
  120.                         connectionMsg = "$msg_session_connected_error";
  121.                         break;
  122.                 };
  123.             });
  124.             //
  125.             $('#oidcinfo')
  126.             .css('color','white')
  127.             .css('padding','3px')
  128.             .css('z-index','10001')
  129.             .css('background-color','#09f')
  130.             .on('click', function(){
  131.                 $('<div></div>').appendTo('body')
  132.                 .html('<div><h6>$infos<br/>$lbl_t_session_restant : ' + timeleft + ' s<br/>$lbl_delai_reponse : ' + responseDelay + ' ms</h6></div>')
  133.                 .dialog({
  134.                     modal: true, title: "$lbl_infos_titre", zIndex: 10000, autoOpen: true,
  135.                     width: 'auto', resizable: false,
  136.                     close: function (event, ui) {
  137.                         $(this).remove();
  138.                         interval = setInterval(pollOidc,pollperiod);
  139.                         }
  140.                     });
  141.                 }
  142.             );            
  143.         }
  144.  
  145.         // If user is logged locally, verify the OIDC session is valid.  
  146.         if ( login !== "" ) {
  147.             pollOidc();
  148.             interval = setInterval(pollOidc,pollperiod);
  149.  
  150.         } else {
  151.             connected = 0;
  152.             // Show not OIDC connected.
  153.             $('#oidctag').css('background-color', 'orange');
  154.             $('#oidctag').text(' OIDC ');
  155.         }
  156.  
  157.         function SessionCloseDialog(message) {    //[dnc28d]
  158.             clearInterval(interval);
  159.             $('<div></div>').appendTo('body')
  160.             .html('<div><h6>'+message+'?</h6></div>')
  161.             .dialog({
  162.                 modal: true, title: "$msg_session_close", zIndex: 10000, autoOpen: true,
  163.                 width: 'auto', resizable: false,
  164.                 buttons: [
  165.                     {
  166.                         text: "$lbl_yes",
  167.                         click: function () {
  168.                             // Close the OIDC session.
  169.                             window.location.replace("$url_logout");
  170.                             $(this).dialog("close");
  171.                         }
  172.                     },{
  173.                         text: "$lbl_no",
  174.                         click: function () {                                                              
  175.                             $(this).dialog("close");
  176.                             interval = setInterval(pollOidc,pollperiod);
  177.                         }
  178.                     }
  179.                 ],
  180.                 close: function (event, ui) {
  181.                     $(this).remove();
  182.                     interval = setInterval(pollOidc,pollperiod);
  183.                 }
  184.             });
  185.         };
  186.  
  187.         function SessionOpenDialog(message) {    //[dnc28d]
  188.             clearInterval(interval);
  189.             $('<div></div>').appendTo('body')
  190.             .html('<div><h6>'+message+'?</h6></div>')
  191.             .dialog({
  192.                 modal: true, title: "$msg_session_open", zIndex: 10000, autoOpen: true,
  193.                 width: 'auto', resizable: false,
  194.                 buttons: [
  195.                     {
  196.                         text: "$lbl_yes",
  197.                         click: function () {
  198.                             // Se connecter
  199.                             window.location.replace("$link_login");
  200.                             $(this).dialog("close");
  201.                         }
  202.                     },{
  203.                         text: "$lbl_no",
  204.                         click: function () {                                                                
  205.                             $(this).dialog("close");
  206.                             interval = setInterval(pollOidc,pollperiod);
  207.                         }
  208.                     }
  209.                 ],
  210.                 close: function (event, ui) {
  211.                     $(this).remove();
  212.                     interval = setInterval(pollOidc,pollperiod);
  213.                 }
  214.             });
  215.         };
  216.  
  217.         function ExtendDialog(message) {    //[dnc28d]
  218.             if ( !$("#extenddialog").size() ) {  //[dnc28f]
  219.                 clearInterval(interval);
  220.                 $('<div id="extendeddialog"></div>').appendTo('body')
  221.                 .html('<div><h6>'+message+'?</h6></div>')
  222.                 .dialog({
  223.                     modal: true, title: "$msg_session_extend", zIndex: 10000, autoOpen: true,
  224.                     width: 'auto', resizable: false,
  225.                     buttons: [
  226.                         {
  227.                             text: "$lbl_yes",
  228.                             click: function () {
  229.                                 // Extend session
  230.                                 $.ajax({
  231.                                     type : "get",
  232.                                     url : "$url_endpoint_login",
  233.                                     data : { 'response_type' : 'code',
  234.                                         'client_id' : "$clientID",
  235.                                         'user_id' : login,
  236.                                         'state' :  "$state",
  237.                                         'scope' : 'openid sli',
  238.                                     }
  239.                                 });
  240.                                 $(this).dialog("close");
  241.                                 interval = setInterval(pollOidc,pollperiod);
  242.                             }
  243.                         },{
  244.                             text: "$lbl_no",
  245.                             click: function () {                                                                
  246.                                 $(this).dialog("close");
  247.                                 interval = setInterval(pollOidc,pollperiod);
  248.                             },
  249.                         }
  250.                     ],
  251.                     close: function (event, ui) {
  252.                         $(this).remove();
  253.                         interval = setInterval(pollOidc,pollperiod);
  254.                     },
  255.                 });
  256.             }
  257.         };
  258.  
  259.         // Test OIDC connection.
  260.         function pollOidc(){
  261.             connected = -1;
  262.             var d = new Date();
  263.             var timeStart = d.getTime();
  264.             var timeStop = 0;
  265.             $.ajax({
  266.                 type : "get",
  267.                 url : "$url_endpoint_login",
  268.                 data : { 'response_type' : 'code',
  269.                     'client_id' : "$clientID",
  270.                     'user_id' : login,
  271.                     'state' :  "$state",
  272.                     'scope' : 'openid',
  273.                     'prompt' : 'none',
  274.                 },
  275.                 statusCode : {
  276.                     401 : function(){
  277.                         connected = 0;
  278.                         var d = new Date();
  279.                         timeStop = d.getTime();
  280.                         // Not (or no longer) connected on OIDC, disconnect locally
  281.                         window.location.replace("$url_logout" +"&logout=local");
  282.                     },
  283.                     200 : function ( data, textStatus, jqXHR){
  284.                         connected = 1;
  285.                         var d = new Date();
  286.                         timeStop = d.getTime();
  287.                         // Show OIDC connected
  288.                         $('#oidctag').css('background-color', '#8f8');
  289.                         $('#oidctag').text(' OIDC ');
  290.                         timeleft = data['timeleft'];
  291.                         if ( timeleft < 600 ) {  //[dnc28d]
  292.                             // Approaching OIDC session end.
  293.                             clearInterval(interval);
  294.                             ExtendDialog("$msg_session_expires");
  295.                             interval = setInterval(pollOidc,pollperiod);
  296.                         }
  297.                     },
  298.                 },
  299.                 error : function(obj,textStatus,errorThrown){
  300.                     connected = -1;
  301.                     // Show error (OIDC state is unknown)
  302.                     $('#oidctag').css('background-color', 'red');
  303.                     $('#oidctag').text(textStatus + ' ' + errorThrown);
  304.                 },
  305.                 complete : function ( data, textStatus, jqXHR){
  306.                     if ( timeStop && timeStart ) {
  307.                         responseDelay = timeStop - timeStart;      
  308.                     } else {
  309.                         responseDelay = 'Unk';
  310.                     }
  311.                 },
  312.             });    
  313.         }
  314.  
  315.     });
  316. })( jQuery );
  317.  
  318. </script>
  319.  
  320. JSCODE
  321. ;
  322.    
  323. } //function

Télécharger

Notons qu’il faut insérer un bloc div en bas de page, ce qui est fait au moyen d’une action dans la fonction bootstrap en même temps que le hook de la fonction précédente :
[PHP]

  1. //OIDC Monitoring
  2.         wp_enqueue_script("jquery");
  3.         add_action('wp_footer', array( $plugin, 'insert_monitoring'), 5);

Télécharger