diff --git a/VERSIONS_HOTLINE/74731 b/VERSIONS_HOTLINE/74731
new file mode 100644
index 0000000000000000000000000000000000000000..be91e0409bd1fa8bc151bdd8c19cbadcab689957
--- /dev/null
+++ b/VERSIONS_HOTLINE/74731
@@ -0,0 +1 @@
+ - ticket #74731 : Connecteur Skilleos
\ No newline at end of file
diff --git a/library/Class/DigitalResource/Config.php b/library/Class/DigitalResource/Config.php
index 6e0eb99b83a4e4b6534c7c282f273497ddcac115..84a2f333828c1509e3af56a0c9d7101a18611103 100644
--- a/library/Class/DigitalResource/Config.php
+++ b/library/Class/DigitalResource/Config.php
@@ -244,4 +244,42 @@ class Class_DigitalResource_Config extends Class_Entity {
     $service = $this->getService();
     return new $service($this);
   }
+
+
+  public function renderHarvestDiagOn($view) {
+    return $view->tag('p',
+                      $this->_('Cette ressource ne prend pas en charge l\'affichage du l\'url de moissonnage'), ['class' => 'error']);
+  }
+
+
+  public function getTestUser() {
+    $login = $this->getName() . '_test_user';
+    $user = ($user = Class_Users::findFirstBy(['login' => $login]))
+      ? $user
+      : Class_Users::newInstance(['login' => $login,
+                                      'password' => $login]);
+
+    $user->save();
+    $group = $this->getTestGroup();
+    $group->addUser($user)->save();
+
+    return $user;
+  }
+
+
+  public function getTestGroup() {
+    $group_name = $this->getName() . '_test_group';
+    $group = ($group = Class_UserGroup::findFirstBy(['libelle' => $group_name]))
+      ? $group
+      : Class_UserGroup::newInstance(['libelle' => $group_name]);
+
+    $group->save();
+
+    if(!$permission = Class_Permission::findFirstBy(['code' => $this->getName()]))
+       return $group;
+
+    $permission->permitTo($group, new Class_Entity());
+
+    return $group;
+  }
 }
\ No newline at end of file
diff --git a/library/Class/DigitalResource/Controller.php b/library/Class/DigitalResource/Controller.php
index 311a8676ee81e04b0a6d88277cfca3be9c5084a6..faabadc2616c5464a672e46889dc1e2964a07dbc 100644
--- a/library/Class/DigitalResource/Controller.php
+++ b/library/Class/DigitalResource/Controller.php
@@ -62,6 +62,17 @@ class Class_DigitalResource_Controller extends ZendAfi_Controller_Action {
   }
 
 
+  public function trySsoAction() {
+    if (!Class_Users::getIdentity()->isSuperAdmin()) {
+      $this->_helper->notify($this->_('Vous n\'avez pas les droits suffisants pour utiliser cette fonctionnalité.'));
+      return $this->_redirectToReferer();
+    }
+
+    ZendAfi_Auth::getInstance()->logUser($this->_config->getTestUser());
+    $this->_forward('sso');
+  }
+
+
   protected function _afterLoginRedirectTo($url, $message = null) {
     if($message)
       $this->_helper->notify($message);
diff --git a/library/ZendAfi/View/Helper/DigitalResource/Dashboard.php b/library/ZendAfi/View/Helper/DigitalResource/Dashboard.php
index 4ff706990c75a8e7fd0eb0b51d9c163866ec388b..4cdbb5448821f5940ae22e47f01917f9f1cf7607 100644
--- a/library/ZendAfi/View/Helper/DigitalResource/Dashboard.php
+++ b/library/ZendAfi/View/Helper/DigitalResource/Dashboard.php
@@ -192,24 +192,8 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard extends ZendAfi_View_Helper_
       return implode($html);
     }
 
-    $login = $this->_config->getName() . '_test_user';
-    $user = ($user = Class_Users::findFirstBy(['login' => $login]))
-      ? $user
-      : Class_Users::newInstance(['login' => $login,
-                                  'password' => $login]);
-
-    $user->save();
-
-    if(!$permission = Class_Permission::findFirstBy(['code' => $this->_config->getName()]))
-      return implode($html);
-
-    $group_name = $this->_config->getName() . '_test_group';
-    $group = ($group = Class_UserGroup::findFirstBy(['libelle' => $group_name]))
-      ? $group
-      : Class_UserGroup::newInstance(['libelle' => $group_name]);
-
-    $group->addUser($user)->save();
-    $permission->permitTo($group, new Class_Entity());
+    $user = $this->_config->getTestUser();
+    $group = $this->_config->getTestGroup();
 
     $html [] = $this->_tag('h5', $this->_('Groupe créé pour ce test'))
       . $this->_tag('ul',
@@ -238,7 +222,11 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard extends ZendAfi_View_Helper_
     $html [] = $this->_tag('h4', $this->_('URL SSO générée par /modules/%s pour l\'utilisateur "%s"',
                                           $this->_config->getSsoAction(),
                                           $user->getLogin()))
-      . $this->view->tagAnchor($url, $url, ['target' => '_blank']);
+      . $this->_tag('pre', $url)
+      . $this->view->button((new Class_Entity)
+                            ->setUrl($this->view->url(['action' => 'try-sso']))
+                            ->setText($this->_('Essayer le SSO avec l\'utilisateur "%s"',
+                                               $user->getLogin())));
 
     if(!$this->_config->getSsoValidateUrl()) {
       $html [] = $this->_tag('p', $this->_('Cette ressource ne prend pas en charge la validation du ticket de connexion SSO'), ['class' => 'error']) ;
@@ -248,7 +236,7 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard extends ZendAfi_View_Helper_
       $url = $this->_config->validateUrlFor($user);
       $html [] = $this->_tag('h4', $this->_('URL de validation du ticket de connexion générée pour l\'utilisateur "%s"',
                                             $user->getLogin()))
-        . $this->view->tagAnchor($url, $url, ['target' => '_blank']);
+        . $this->_tag('pre', $url);
     }
 
 
@@ -337,10 +325,8 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard extends ZendAfi_View_Helper_
     $html [] = ($url = $this->_config->getHarvestUrl())
       ? ($this->_tag('h4',
                     $this->_('URL de moissonnage générée pour la première page'))
-         . $this->view->tagAnchor($url,
-                                  $url,
-                                  ['target' => '_blank']))
-      : $this->_tag('p', $this->_('Cette ressource ne prend pas en charge l\'affichage du l\'url de moissonnage'), ['class' => 'error']);
+         . $this->_tag('pre', $url))
+      : $this->_config->renderHarvestDiagOn($this->view);
 
     $html [] = $this->_tag('h4',
                            $this->_('Image du type de document: ')
@@ -370,9 +356,8 @@ class ZendAfi_View_Helper_DigitalResource_Dashboard extends ZendAfi_View_Helper_
     $html [] = $count
       ? ($this->_tag('h4',
                      $this->_('Tentative de vignettage de l\'album "%s" : ', $first_album->getTitre()))
-         . $this->view->tagAnchor($first_album->getPoster(),
-                             $this->_('Image source : %s', $first_album->getPoster()),
-                             ['target' => '_blank'])
+         . $this->_tag('pre',
+                       $this->_('Image source : %s', $first_album->getPoster()))
          . $this->_renderThumbnailerLog($first_album))
       : $this->_tag('p', $this->_('Le vignettage n\'est pas testable sans album'), ['class' => 'error']);
 
diff --git a/library/digital_resources/Skilleos/Config.php b/library/digital_resources/Skilleos/Config.php
index 0d5a34b0d6f5592b8c3c13e9a6171682233e09d1..3f7274d0d5ec57fc759a72b866c5b8e0eba00406 100644
--- a/library/digital_resources/Skilleos/Config.php
+++ b/library/digital_resources/Skilleos/Config.php
@@ -76,4 +76,25 @@ class Skilleos_Config extends Class_DigitalResource_Config {
   public function isEnabled() {
     return  '' != $this->getAdminVar('BIB_ID');
   }
+
+
+  public function renderHarvestDiagOn($view) {
+    $service = $this->getServiceInstance();
+
+    $token_url = $service->getTokenUrl();
+    $catalogue_url = Skilleos_Service::$REST_URL;
+
+    $html = [$view->tag('p', $this->_('Ce moissonnage se compose de deux étapes:')),
+             $view->tag('h4', $this->_('Première étape: La récupération du token OAUTH à l\'adresse:')),
+             $view->tag('pre', $token_url),
+             $view->tag('p', $this->_('Réponse reçue à la demande de token :')),
+             $view->tag('pre', $service->httpGet($token_url)),
+             $view->tag('h4', $this->_('Deuxième étape: La récupération du catalogue à l\'adresse:')),
+             $view->tag('pre', $catalogue_url),
+             $view->tag('p', $this->_('Réponse reçue à la demande du catalogue:')),
+             $view->tag('pre', $service->httpGetCatalogue()),
+    ];
+
+    return implode($html);
+  }
 }
diff --git a/library/digital_resources/Skilleos/Service.php b/library/digital_resources/Skilleos/Service.php
index c59f7ed9f725d4218d32d4cfbf26b15ecf6080c0..8add35178f134960aefd25c02d8d80bd0a2a9b0c 100644
--- a/library/digital_resources/Skilleos/Service.php
+++ b/library/digital_resources/Skilleos/Service.php
@@ -37,11 +37,7 @@ class Skilleos_Service extends Class_DigitalResource_Service {
 
 
   protected function getToken() {
-    $query = ['grant_type' => 'client_credentials',
-              'client_id' => $this->_config->getAdminVar('CLIENT_ID'),
-              'client_secret' => $this->_config->getAdminVar('CLIENT_SECRET')];
-
-    $url = static::$TOKEN_URL . '?' . http_build_query($query);
+    $url = $this->getTokenUrl();
 
     if(!$response = $this->httpGet($url))
       return;
@@ -52,9 +48,17 @@ class Skilleos_Service extends Class_DigitalResource_Service {
   }
 
 
+  public function getTokenUrl() {
+    $query = ['grant_type' => 'client_credentials',
+              'client_id' => $this->_config->getAdminVar('CLIENT_ID'),
+              'client_secret' => $this->_config->getAdminVar('CLIENT_SECRET')];
+
+    return static::$TOKEN_URL . '?' . http_build_query($query);
+  }
+
+
   protected function loadPage($page_number = 1) {
-    $response = $this->httpGet(static::$REST_URL,
-                               ['headers' => [ 'Authorization' => 'Bearer ' . $this->getToken()]]);
+    $response = $this->httpGetCatalogue();
 
     if(!$json = json_decode($response))
       return $this;
@@ -68,6 +72,12 @@ class Skilleos_Service extends Class_DigitalResource_Service {
   }
 
 
+  public function httpGetCatalogue() {
+    return $this->httpGet(static::$REST_URL,
+                          ['headers' => [ 'Authorization' => 'Bearer ' . $this->getToken()]]);
+  }
+
+
   public function getPageCount() {
     return 1;
   }
diff --git a/library/digital_resources/Skilleos/tests/SkilleosTest.php b/library/digital_resources/Skilleos/tests/SkilleosTest.php
index e58a6dd042c642b4b8909e9aa65d8801c3ab884e..f93255d6371fa7041692b17637994880030ffa5a 100644
--- a/library/digital_resources/Skilleos/tests/SkilleosTest.php
+++ b/library/digital_resources/Skilleos/tests/SkilleosTest.php
@@ -366,3 +366,49 @@ class SkilleosBatchIndexTest extends Admin_AbstractControllerTestCase {
                                          'Moissonner catalogue Skilleos');
   }
 }
+
+
+
+
+class SkilleosDashboardTest extends SkilleosServiceTestCase {
+  public function setUp() {
+    parent::setUp();
+    $this->dispatch('/Skilleos_Plugin', true);
+  }
+
+
+  /** @test */
+  public function getTokenUrlShouldBePresent() {
+    $this->assertXPathContentContains('//pre', 'http://moncompte.skilleos.com/oauth/v2/token?grant_type=client_credentials');
+  }
+
+
+  /** @test */
+  public function getCatalogueUrlShouldBePresent() {
+    $this->assertXPathContentContains('//pre', 'http://moncompte.skilleos.com/rest/api/trainings');
+  }
+}
+
+
+
+
+class SkilleosDashboardTrySsoTest extends SkilleosServiceTestCase {
+  public function setUp() {
+    parent::setUp();
+
+    $user = $this->fixture('Class_Users',
+                           ['id' => 5,
+                            'login' => 'super_admin',
+                            'password' => 'super',
+                            'role_level' => ZendAfi_Acl_AdminControllerRoles::SUPER_ADMIN]);
+
+    ZendAfi_Auth::getInstance()->logUser($user);
+    $this->dispatch('/Skilleos_Plugin/index/try-sso', true);
+  }
+
+
+  /** @test */
+  public function shouldJavascriptRedirectToMoncompteDotSkilleos() {
+    $this->assertXPathContentContains('//script', 'document.location.href="http://skilleos.com/sigb/sso/?casid=QUEST&ticket');
+  }
+}
\ No newline at end of file
diff --git a/library/digital_resources/StoryPlayR/tests/StoryPlayRTest.php b/library/digital_resources/StoryPlayR/tests/StoryPlayRTest.php
index 4d87e3041104bb2c0271bea25a6a97c993a2cb43..528910038e3198ab35aca0f4814496abcb14bfc2 100644
--- a/library/digital_resources/StoryPlayR/tests/StoryPlayRTest.php
+++ b/library/digital_resources/StoryPlayR/tests/StoryPlayRTest.php
@@ -142,19 +142,19 @@ class StoryPlayRDashboardActivatedTest extends StoryPlayRActivatedTestCase {
 
   /** @test */
   public function testSsoValidateUrlShoudlBeDisplay() {
-    $this->assertXPathContentContains('//a', '/StoryPlayR_Plugin/auth/validate?sessionid=ST-');
+    $this->assertXPathContentContains('//pre', '/StoryPlayR_Plugin/auth/validate?sessionid=ST-');
   }
 
 
   /** @test */
   public function harvestUrlShouldContainsOpdsCatalogUrlAndProviderAndMediathequeid() {
-    $this->assertXPath('//a[@href="https://preprod.storyplayr.com/api/opds-with-links?portalProvider=bokeh&mediathequeid=123456"]');
+    $this->assertXPathContentContains('//pre', 'https://preprod.storyplayr.com/api/opds-with-links?portalProvider=bokeh');
   }
 
 
   /** @test */
   public function sourceImageShouldBeValid() {
-    $this->assertXPathContentContains('//a','Image source : https://preprod');
+    $this->assertXPathContentContains('//pre','Image source : https://preprod');
   }
 
 
diff --git a/public/admin/css/global.css b/public/admin/css/global.css
index fa14ee1bb390c67765f5f1e3b98d357d1303da77..cc30c1dabdeface4cf409ccac67f6d7f3260be69 100644
--- a/public/admin/css/global.css
+++ b/public/admin/css/global.css
@@ -1649,3 +1649,10 @@ table#logs img {
 #learn_more:hover {
   background-color:var(--bokeh-event-highlight);
 }
+
+.modules pre {
+    margin: 1ex 1em;
+    padding: 1ex 1em;
+    overflow: auto;
+    max-height: 300px;
+}
\ No newline at end of file
diff --git a/public/admin/skins/bokeh74/global.css b/public/admin/skins/bokeh74/global.css
index ed171cda6b3e45f07207e82f559272b7f780fc04..f2563311e61a571dfa724a7c4442f0656fb74289 100755
--- a/public/admin/skins/bokeh74/global.css
+++ b/public/admin/skins/bokeh74/global.css
@@ -1019,6 +1019,7 @@ table#logs img {
     margin: 1ex 1em;
     padding: 1ex 1em;
     overflow: auto;
+    max-height: 300px;
 }
 
 #learn_more > * {
diff --git a/public/admin/skins/retro/global.css b/public/admin/skins/retro/global.css
index c97c2f85477ed67274f6eef6adc3a19e77f3f8c1..5fc005922b551b7db669b6c1d5d48988b7a54233 100755
--- a/public/admin/skins/retro/global.css
+++ b/public/admin/skins/retro/global.css
@@ -884,4 +884,11 @@ body .error * {
 
 #learn_more:hover {
   background-color:var(--bokeh-event-highlight);
+}
+
+.modules pre {
+    margin: 1ex 1em;
+    padding: 1ex 1em;
+    overflow: auto;
+    max-height: 300px;
 }
\ No newline at end of file