Minor - Plugin: LTI provider format code #3894

pull/3914/head
Angel Fernando Quiroz Campos 4 years ago committed by Christian
parent 7e8a9b5ccb
commit c794b09bce
  1. 42
      plugin/lti_provider/Entity/Platform.php
  2. 22
      plugin/lti_provider/Entity/PlatformKey.php
  3. 236
      plugin/lti_provider/LtiProviderPlugin.php
  4. 1
      plugin/lti_provider/create.php
  5. 47
      plugin/lti_provider/db/lti13_cache.php
  6. 6
      plugin/lti_provider/db/lti13_cookie.php
  7. 37
      plugin/lti_provider/db/lti13_database.php
  8. 1
      plugin/lti_provider/edit.php
  9. 1
      plugin/lti_provider/install.php
  10. 1
      plugin/lti_provider/plugin.php
  11. 4
      plugin/lti_provider/src/Form/FrmAdd.php
  12. 4
      plugin/lti_provider/src/Form/FrmEdit.php
  13. 45
      plugin/lti_provider/src/LtiProvider.php
  14. 1
      plugin/lti_provider/uninstall.php

@ -71,7 +71,7 @@ class Platform
*
* @return int
*/
public function getId()
public function getId(): int
{
return $this->id;
}
@ -83,7 +83,7 @@ class Platform
*
* @return Platform
*/
public function setId($id)
public function setId(int $id): Platform
{
$this->id = $id;
@ -96,17 +96,27 @@ class Platform
*
* @return string
*/
public function getKid()
public function getKid(): string
{
return $this->kid;
}
/**
* Set kid.
*
* @param string $kid
*/
public function setKid(string $kid)
{
$this->kid = $kid;
}
/**
* Get Issuer
*
* @return string
*/
public function getIssuer()
public function getIssuer(): string
{
return $this->issuer;
}
@ -126,7 +136,7 @@ class Platform
*
* @return string
*/
public function getClientId()
public function getClientId(): string
{
return $this->clientId;
}
@ -146,7 +156,7 @@ class Platform
*
* @return string
*/
public function getAuthLoginUrl()
public function getAuthLoginUrl(): string
{
return $this->authLoginUrl;
}
@ -166,7 +176,7 @@ class Platform
*
* @return string
*/
public function getAuthTokenUrl()
public function getAuthTokenUrl(): string
{
return $this->authTokenUrl;
}
@ -183,15 +193,17 @@ class Platform
/**
* Get key set URL
*
* @return string
*/
public function getKeySetUrl()
public function getKeySetUrl(): string
{
return $this->keySetUrl;
}
/**
* Set key set URL
*
* @param string $keySetUrl
*/
public function setKeySetUrl(string $keySetUrl)
@ -204,7 +216,7 @@ class Platform
*
* @return string
*/
public function getDeploymentId()
public function getDeploymentId(): string
{
return $this->deploymentId;
}
@ -218,16 +230,4 @@ class Platform
{
$this->deploymentId = $deploymentId;
}
/**
* Set kid.
*
* @param string $kid
*/
public function setKid($kid)
{
$this->kid = $kid;
}
}

@ -47,19 +47,15 @@ class PlatformKey
*
* @return int
*/
public function getId()
public function getId(): int
{
return $this->id;
}
/**
* Set id.
*
* @param int $id
*
* @return Platform
*/
public function setId($id)
public function setId(int $id): PlatformKey
{
$this->id = $id;
@ -72,7 +68,7 @@ class PlatformKey
*
* @return string
*/
public function getKid()
public function getKid(): string
{
return $this->kid;
}
@ -82,7 +78,7 @@ class PlatformKey
*
* @param string $kid
*/
public function setKid($kid)
public function setKid(string $kid)
{
$this->kid = $kid;
}
@ -92,7 +88,7 @@ class PlatformKey
*
* @return string
*/
public function getPrivateKey()
public function getPrivateKey(): string
{
return $this->privateKey;
}
@ -102,9 +98,9 @@ class PlatformKey
*
* @param string $privateKey
*
* @return Platform
* @return PlatformKey
*/
public function setPrivateKey($privateKey)
public function setPrivateKey(string $privateKey): PlatformKey
{
$this->privateKey = $privateKey;
@ -114,7 +110,7 @@ class PlatformKey
/**
* @return string
*/
public function getPublicKey()
public function getPublicKey(): string
{
return $this->publicKey;
}
@ -126,6 +122,4 @@ class PlatformKey
{
$this->publicKey = $publicKey;
}
}

@ -3,8 +3,7 @@
use Chamilo\PluginBundle\Entity\LtiProvider\PlatformKey;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;
use Doctrine\ORM\OptimisticLockException;
use Symfony\Component\Filesystem\Filesystem;
/**
@ -32,7 +31,8 @@ class LtiProviderPlugin extends Plugin
}
$pkHtml = '<div class="form-group ">
<label for="lti_provider_public_key" class="col-sm-2 control-label">'.$this->get_lang('PublicKey').'</label>
<label for="lti_provider_public_key" class="col-sm-2 control-label">'
.$this->get_lang('PublicKey').'</label>
<div class="col-sm-8">
<pre>'.$publicKey.'</pre>
<p class="help-block"></p>
@ -47,28 +47,53 @@ class LtiProviderPlugin extends Plugin
'login_url' => 'text',
'redirect_url' => 'text',
$pkHtml => 'html',
'enabled' => 'boolean'
'enabled' => 'boolean',
];
parent::__construct($version, $author, $settings);
}
/**
* Get the public key
*
* @return string
*/
public function getPublicKey(): string
{
$publicKey = '';
$platformKey = Database::getManager()
->getRepository('ChamiloPluginBundle:LtiProvider\PlatformKey')
->findOneBy([]);
if ($platformKey) {
$publicKey = $platformKey->getPublicKey();
}
return $publicKey;
}
/**
* Get the class instance
*
* @staticvar LtiProviderPlugin $result
* @return LtiProviderPlugin
*/
public static function create()
public static function create(): LtiProviderPlugin
{
static $result = null;
return $result ?: $result = new self();
}
public static function isInstructor()
{
api_is_allowed_to_edit(false, true);
}
/**
* Get the plugin directory name
*/
public function get_name()
public function get_name(): string
{
return 'lti_provider';
}
@ -85,7 +110,7 @@ class LtiProviderPlugin extends Plugin
$message = get_lang('ErrorCreatingDir').': '.$pluginEntityPath;
Display::addFlash(Display::return_message($message, 'error'));
return false;
return;
}
mkdir($pluginEntityPath, api_get_permissions_for_new_directories());
@ -98,78 +123,25 @@ class LtiProviderPlugin extends Plugin
}
/**
* Save configuration for plugin.
*
* Generate a new key pair for platform when enabling plugin.
*
* @throws \Doctrine\ORM\OptimisticLockException
*
* @return $this|Plugin
*/
public function performActionsAfterConfigure()
{
$em = Database::getManager();
/** @var PlatformKey $platformKey */
$platformKey = $em
->getRepository('ChamiloPluginBundle:LtiProvider\PlatformKey')
->findOneBy([]);
if ($this->get('enabled') === 'true') {
if (!$platformKey) {
$platformKey = new PlatformKey();
}
$keyPair = self::generatePlatformKeys();
$platformKey->setKid($keyPair['kid']);
$platformKey->publicKey = $keyPair['public'];
$platformKey->setPrivateKey($keyPair['private']);
$em->persist($platformKey);
} else {
if ($platformKey) {
$em->remove($platformKey);
}
}
$em->flush();
return $this;
}
/**
* Unistall plugin. Clear the database
* @return string
*/
public function uninstall()
public function getEntityPath(): string
{
$pluginEntityPath = $this->getEntityPath();
$fs = new Filesystem();
if ($fs->exists($pluginEntityPath)) {
$fs->remove($pluginEntityPath);
}
try {
$this->dropPluginTables();
} catch (DBALException $e) {
error_log('Error while uninstalling IMS/LTI plugin: '.$e->getMessage());
}
return api_get_path(SYS_PATH).'src/Chamilo/PluginBundle/Entity/'.$this->getCamelCaseName();
}
/**
* Creates the plugin tables on database
*
* @return boolean
* @throws DBALException
* @return void
*/
private function createPluginTables()
private function createPluginTables(): void
{
$entityManager = Database::getManager();
$connection = $entityManager->getConnection();
if ($connection->getSchemaManager()->tablesExist(self::TABLE_PLATFORM)) {
return true;
return;
}
$queries = [
@ -190,64 +162,55 @@ class LtiProviderPlugin extends Plugin
public_key LONGTEXT NOT NULL,
private_key LONGTEXT NOT NULL,
PRIMARY KEY(id)
) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB"
) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB",
];
foreach ($queries as $query) {
Database::query($query);
}
return true;
}
/**
* Drops the plugin tables on database
* Save configuration for plugin.
*
* @return boolean
* Generate a new key pair for platform when enabling plugin.
*
* @throws OptimisticLockException
* @throws \Doctrine\ORM\ORMException
*
* @return $this|Plugin
*/
private function dropPluginTables()
public function performActionsAfterConfigure()
{
Database::query("DROP TABLE IF EXISTS plugin_lti_provider_platform");
Database::query("DROP TABLE IF EXISTS plugin_lti_provider_platform_key");
return true;
}
$em = Database::getManager();
/**
* @return string
*/
public function getEntityPath()
{
return api_get_path(SYS_PATH).'src/Chamilo/PluginBundle/Entity/'.$this->getCamelCaseName();
}
/** @var PlatformKey $platformKey */
$platformKey = $em
->getRepository('ChamiloPluginBundle:LtiProvider\PlatformKey')
->findOneBy([]);
public static function isInstructor()
{
api_is_allowed_to_edit(false, true);
if ($this->get('enabled') === 'true') {
if (!$platformKey) {
$platformKey = new PlatformKey();
}
/**
* @return null|SimpleXMLElement
*/
private function getRequestXmlElement()
{
$request = file_get_contents("php://input");
$keyPair = self::generatePlatformKeys();
if (empty($request)) {
return null;
}
$platformKey->setKid($keyPair['kid']);
$platformKey->publicKey = $keyPair['public'];
$platformKey->setPrivateKey($keyPair['private']);
return new SimpleXMLElement($request);
$em->persist($platformKey);
} else {
if ($platformKey) {
$em->remove($platformKey);
}
/**
* @param array $params
*/
public function trimParams(array &$params)
{
foreach ($params as $key => $value) {
$newValue = preg_replace('/\s+/', ' ', $value);
$params[$key] = trim($newValue);
}
$em->flush();
return $this;
}
/**
@ -257,7 +220,7 @@ class LtiProviderPlugin extends Plugin
*
* @return array
*/
private static function generatePlatformKeys()
private static function generatePlatformKeys(): array
{
// Create the private and public key
$res = openssl_pkey_new(
@ -283,19 +246,62 @@ class LtiProviderPlugin extends Plugin
}
/**
* Get the public key
* Unistall plugin. Clear the database
*/
public function uninstall()
{
$pluginEntityPath = $this->getEntityPath();
$fs = new Filesystem();
if ($fs->exists($pluginEntityPath)) {
$fs->remove($pluginEntityPath);
}
try {
$this->dropPluginTables();
} catch (DBALException $e) {
error_log('Error while uninstalling IMS/LTI plugin: '.$e->getMessage());
}
}
/**
* Drops the plugin tables on database
*
* @return string
* @return boolean
*/
public function getPublicKey() {
$publicKey = '';
$platformKey = Database::getManager()
->getRepository('ChamiloPluginBundle:LtiProvider\PlatformKey')
->findOneBy([]);
if ($platformKey) {
$publicKey = $platformKey->getPublicKey();
private function dropPluginTables(): bool
{
Database::query("DROP TABLE IF EXISTS plugin_lti_provider_platform");
Database::query("DROP TABLE IF EXISTS plugin_lti_provider_platform_key");
return true;
}
return $publicKey;
/**
* @param array $params
*/
public function trimParams(array &$params)
{
foreach ($params as $key => $value) {
$newValue = preg_replace('/\s+/', ' ', $value);
$params[$key] = trim($newValue);
}
}
/**
* @throws Exception
*
* @return null|SimpleXMLElement
*/
private function getRequestXmlElement(): ?SimpleXMLElement
{
$request = file_get_contents("php://input");
if (empty($request)) {
return null;
}
return new SimpleXMLElement($request);
}
}

@ -1,5 +1,6 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Entity\LtiProvider\Platform;
$cidReset = true;

@ -3,48 +3,57 @@
use Packback\Lti1p3\Interfaces\Cache as Lti1p3Cache;
class Lti13Cache implements Lti1p3Cache
{
public const NONCE_PREFIX = 'nonce_';
private $cache;
public function getLaunchData($key) {
public function getLaunchData($key)
{
$this->loadCache();
return $this->cache[$key];
}
public function cacheLaunchData($key, $jwt_body) {
$this->cache[$key] = $jwt_body;
private function loadCache()
{
$cache = file_get_contents(sys_get_temp_dir().'/lti_cache.txt');
if (empty($cache)) {
file_put_contents(sys_get_temp_dir().'/lti_cache.txt', '{}');
$this->cache = [];
}
$this->cache = json_decode($cache, true);
}
public function cacheLaunchData($key, $jwtBody): Lti13Cache
{
$this->cache[$key] = $jwtBody;
$this->saveCache();
return $this;
}
public function cacheNonce($nonce) {
private function saveCache()
{
file_put_contents(sys_get_temp_dir().'/lti_cache.txt', json_encode($this->cache));
}
public function cacheNonce($nonce): Lti13Cache
{
$this->cache['nonce'][$nonce] = true;
$this->saveCache();
return $this;
}
public function checkNonce($nonce) {
public function checkNonce($nonce): bool
{
$this->loadCache();
if (!isset($this->cache['nonce'][$nonce])) {
return false;
}
return true;
}
private function loadCache() {
$cache = file_get_contents(sys_get_temp_dir() . '/lti_cache.txt');
if (empty($cache)) {
file_put_contents(sys_get_temp_dir() . '/lti_cache.txt', '{}');
$this->cache = [];
}
$this->cache = json_decode($cache, true);
}
private function saveCache() {
file_put_contents(sys_get_temp_dir() . '/lti_cache.txt', json_encode($this->cache));
return true;
}
}

@ -14,26 +14,28 @@ class Lti13Cookie implements Lti1p3Cookie
if (isset($_COOKIE["LEGACY_".$name])) {
return $_COOKIE["LEGACY_".$name];
}
return false;
}
public function setCookie($name, $value, $exp = 3600, $options = []): self
{
$cookieOptions = [
'expires' => time() + $exp
'expires' => time() + $exp,
];
// SameSite none and secure will be required for tools to work inside iframes
$sameSiteOptions = [
'samesite' => 'None',
'secure' => false,
'httponly' => true
'httponly' => true,
];
setcookie($name, $value, array_merge($cookieOptions, $sameSiteOptions, $options));
// Set a second fallback cookie in the event that "SameSite" is not supported
setcookie("LEGACY_".$name, $value, array_merge($cookieOptions, $options));
return $this;
}
}

@ -1,19 +1,16 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Entity\LtiProvider\Platform;
use Chamilo\PluginBundle\Entity\LtiProvider\PlatformKey;
use ChamiloSession as Session;
use Packback\Lti1p3;
use Packback\Lti1p3\Interfaces;
use Packback\Lti1p3\LtiRegistration;
use Packback\Lti1p3\LtiDeployment;
use Packback\Lti1p3\OidcException;
use Packback\Lti1p3\LtiRegistration;
class Lti13Database implements Interfaces\Database
{
public function findRegistrationByIssuer($iss, $clientId = null) {
public function findRegistrationByIssuer($iss, $clientId = null)
{
$ltiCustomers = $this->getLtiConnection();
if (empty($ltiCustomers[$iss])) {
return false;
@ -33,16 +30,8 @@ class Lti13Database implements Interfaces\Database
->setToolPrivateKey($this->getPrivateKey());
}
public function findDeployment($iss, $deploymentId, $clientId = null) {
if (!in_array($deploymentId, $_SESSION['iss'][$iss]['deployment'])) {
return false;
}
return LtiDeployment::new()
->setDeploymentId($deploymentId);
}
private function getLtiConnection() {
private function getLtiConnection(): array
{
$em = Database::getManager();
$platforms = $em->getRepository('ChamiloPluginBundle:LtiProvider\Platform')->findAll();
@ -55,14 +44,16 @@ class Lti13Database implements Interfaces\Database
'auth_token_url' => $platform->getAuthTokenUrl(),
'key_set_url' => $platform->getKeySetUrl(),
'kid' => $platform->getKid(),
'deployment' => [$platform->getDeploymentId()]
'deployment' => [$platform->getDeploymentId()],
];
}
Session::write('iss', $ltiCustomers);
return $ltiCustomers;
}
private function getPrivateKey() {
private function getPrivateKey()
{
$privateKey = '';
$platformKey = Database::getManager()
->getRepository('ChamiloPluginBundle:LtiProvider\PlatformKey')
@ -70,6 +61,16 @@ class Lti13Database implements Interfaces\Database
if ($platformKey) {
$privateKey = $platformKey->getPrivateKey();
}
return $privateKey;
}
public function findDeployment($iss, $deploymentId, $clientId = null)
{
if (!in_array($deploymentId, $_SESSION['iss'][$iss]['deployment'])) {
return false;
}
return LtiDeployment::new()->setDeploymentId($deploymentId);
}
}

@ -1,5 +1,6 @@
<?php
/* For license terms, see /license.txt */
use Chamilo\PluginBundle\Entity\LtiProvider\Platform;
$cidReset = true;

@ -3,6 +3,7 @@
/**
* Install the Lti/Provider Plugin
*
* @package chamilo.plugin.lti_provider
*/
require_once __DIR__.'/../../main/inc/global.inc.php';

@ -1,5 +1,6 @@
<?php
/* For license terms, see /license.txt */
require_once __DIR__.'/LtiProviderPlugin.php';
$plugin_info = LtiProviderPlugin::create()->get_info();

@ -25,7 +25,7 @@ class FrmAdd extends FormValidator
$attributes = [],
Platform $platform = null
) {
parent::__construct($name, 'POST', '', '', $attributes, self::LAYOUT_HORIZONTAL, true);
parent::__construct($name, 'POST', '', '', $attributes, self::LAYOUT_HORIZONTAL);
$this->platform = $platform;
}
@ -71,7 +71,7 @@ class FrmAdd extends FormValidator
$this->setDefaults($defaults);
}
public function returnForm()
public function returnForm(): string
{
$js = "<script>
</script>";

@ -25,7 +25,7 @@ class FrmEdit extends FormValidator
$attributes = [],
Platform $platform = null
) {
parent::__construct($name, 'POST', '', '', $attributes, self::LAYOUT_HORIZONTAL, true);
parent::__construct($name, 'POST', '', '', $attributes, self::LAYOUT_HORIZONTAL);
$this->platform = $platform;
}
@ -37,7 +37,7 @@ class FrmEdit extends FormValidator
*
* @throws Exception
*/
public function build($globalMode = true)
public function build(bool $globalMode = true)
{
$plugin = LtiProviderPlugin::create();
$this->addHeader($plugin->get_lang('ConnectionDetails'));

@ -2,15 +2,13 @@
/* For licensing terms, see /license.txt */
use Packback\Lti1p3;
use Packback\Lti1p3\LtiMessageLaunch;
use Packback\Lti1p3\LtiOidcLogin;
require_once __DIR__.'/../db/lti13_cookie.php';
require_once __DIR__.'/../db/lti13_cache.php';
require_once __DIR__.'/../db/lti13_database.php';
use Packback\Lti1p3\LtiOidcLogin;
use Packback\Lti1p3\LtiMessageLaunch;
/**
* Class LtiProvider
@ -18,10 +16,26 @@ use Packback\Lti1p3\LtiMessageLaunch;
class LtiProvider
{
/**
* Get the class instance
*
* @staticvar LtiProvider $result
* @return LtiProvider
*/
public static function create()
{
static $result = null;
return $result ?: $result = new self();
}
/**
* Oidc login and register
*
* @throws Lti1p3\OidcException
*/
public function login($request = null) {
public function login($request = null)
{
LtiOidcLogin::new(new Lti13Database, new Lti13Cache(), new Lti13Cookie)
->doOidcLoginRedirect(api_get_path(WEB_PLUGIN_PATH)."lti_provider/web/game.php", $request)
->doRedirect();
@ -29,28 +43,23 @@ class LtiProvider
/**
* Lti Message Launch
*
* @param bool $fromCache
* @param null $launchId
* return $launch
*
* @throws Lti1p3\LtiException
*
* @return LtiMessageLaunch
*/
public function launch($fromCache = false, $launchId = null) {
public function launch(bool $fromCache = false, $launchId = null): LtiMessageLaunch
{
if ($fromCache) {
$launch = LtiMessageLaunch::fromCache($launchId, new Lti13Database(), new Lti13Cache());
} else {
$launch = LtiMessageLaunch::new(new Lti13Database(), new Lti13Cache(), new Lti13Cookie)->validate();
}
return $launch;
}
/**
* Get the class instance
* @staticvar LtiProvider $result
* @return LtiProvider
*/
public static function create()
{
static $result = null;
return $result ?: $result = new self();
return $launch;
}
}

@ -3,6 +3,7 @@
/**
* Install the Lti/Provider Plugin
*
* @package chamilo.plugin.lti_provider
*/
require_once __DIR__.'/../../main/inc/global.inc.php';

Loading…
Cancel
Save