Skip to content

Commit

Permalink
LTI: Adding advantage services + fix token
Browse files Browse the repository at this point in the history
  • Loading branch information
AngelFQC committed Dec 25, 2019
1 parent 6effdea commit 2ec596b
Show file tree
Hide file tree
Showing 10 changed files with 413 additions and 35 deletions.
24 changes: 24 additions & 0 deletions plugin/ims_lti/Entity/ImsLtiTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ class ImsLtiTool
*/
private $redirectUrl;

/**
* @var array
*
* @ORM\Column(name="advantage_services", type="json", nullable=true)
*/
private $advantageServices;

/**
* ImsLtiTool constructor.
*/
Expand Down Expand Up @@ -621,4 +628,21 @@ public function setClientId($clientId)

return $this;
}

/**
* @return array
*/
public function getAdvantageServices()
{
if (empty($this->advantageServices)) {
return [];
}

return array_merge(
[
'ags' => \LtiAdvantageService::AGS_SIMPLE,
],
$this->advantageServices
);
}
}
187 changes: 187 additions & 0 deletions plugin/ims_lti/Entity/Token.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
<?php
/* For licensing terms, see /license.txt */

namespace Chamilo\PluginBundle\Entity\ImsLti;

use Doctrine\ORM\Mapping as ORM;

/**
* Class Token.
*
* @package Chamilo\PluginBundle\Entity\ImsLti
*
* @ORM\Table(name="plugin_ims_lti_token")
* @ORM\Entity()
*/
class Token
{
const TOKEN_LIFETIME = 3600;

/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id()
* @ORM\GeneratedValue()
*/
protected $id;
/**
* @var ImsLtiTool
*
* @ORM\ManyToOne(targetEntity="Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool")
* @ORM\JoinColumn(name="tool_id", referencedColumnName="id")
*/
private $tool;
/**
* @var array
*
* @ORM\Column(name="scope", type="json")
*/
private $scope;
/**
* @var string
*
* @ORM\Column(name="hash", type="string")
*/
private $hash;
/**
* @var int
*
* @ORM\Column(name="created_at", type="integer")
*/
private $createdAt;
/**
* @var int
*
* @ORM\Column(name="expires_at", type="integer")
*/
private $expiresAt;

/**
* @return int
*/
public function getId()
{
return $this->id;
}

/**
* @return ImsLtiTool
*/
public function getTool()
{
return $this->tool;
}

/**
* @param ImsLtiTool $tool
*
* @return Token
*/
public function setTool($tool)
{
$this->tool = $tool;

return $this;
}

/**
* @return array
*/
public function getScope()
{
return $this->scope;
}

/**
* @param array $scope
*
* @return Token
*/
public function setScope($scope)
{
$this->scope = $scope;

return $this;
}

/**
* @return string
*/
public function getHash()
{
return $this->hash;
}

/**
* @param string $hash
*
* @return Token
*/
public function setHash($hash)
{
$this->hash = $hash;

return $this;
}

/**
* @return int
*/
public function getCreatedAt()
{
return $this->createdAt;
}

/**
* @param int $createdAt
*
* @return Token
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;

return $this;
}

/**
* @return int
*/
public function getExpiresAt()
{
return $this->expiresAt;
}

/**
* @param int $expiresAt
*
* @return Token
*/
public function setExpiresAt($expiresAt)
{
$this->expiresAt = $expiresAt;

return $this;
}

/**
* @return string
*/
public function getScopeInString()
{
return implode(' ', $this->scope);
}

/**
* Generate unique hash.
*
* @return Token
*/
public function generateHash()
{
$this->hash = sha1(uniqid(mt_rand()));

return $this;
}
}
5 changes: 5 additions & 0 deletions plugin/ims_lti/gradebook/service/lineitem.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/* For licensing terms, see /license.txt */

require_once __DIR__.'/../../main/inc/global.inc.php';

5 changes: 5 additions & 0 deletions plugin/ims_lti/gradebook/service/result.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/* For licensing terms, see /license.txt */

require_once __DIR__.'/../../main/inc/global.inc.php';

5 changes: 5 additions & 0 deletions plugin/ims_lti/gradebook/service/score.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php
/* For licensing terms, see /license.txt */

require_once __DIR__.'/../../main/inc/global.inc.php';

15 changes: 15 additions & 0 deletions plugin/ims_lti/src/ImsLti.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

use Chamilo\CoreBundle\Entity\Course;
use Chamilo\CoreBundle\Entity\Session;
use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool;
use Chamilo\UserBundle\Entity\User;

/**
Expand Down Expand Up @@ -177,4 +178,18 @@ public static function getCourseSectionSourcedId($domain, Course $course, Sessio

return implode(':', $sourceId);
}

/**
* Get instances for LTI Advantage services.
*
* @param ImsLtiTool $tool
*
* @return array
*/
public static function getAdvantageServices(ImsLtiTool $tool)
{
return [
new LtiAssignmentGradesService($tool),
];
}
}
82 changes: 82 additions & 0 deletions plugin/ims_lti/src/Request/LtiTokenRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php
/* For licensing terms, see /license.txt */

use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool;
use Firebase\JWT\JWT;

/**
* Class LtiTokenRequest.
*/
class LtiTokenRequest
{
/**
* Validate the request's client assertion. Return the right tool.
*
* @param string $clientAssertion
*
* @throws Exception
*
* @return ImsLtiTool
*/
public function validateClientAssertion($clientAssertion)
{
$parts = explode('.', $clientAssertion);

if (count($parts) !== 3) {
throw new Exception('invalid_request');
}

$payload = JWT::urlsafeB64Decode($parts[1]);
$claims = json_decode($payload, true);

if (empty($claims) || empty($claims['sub'])) {
throw new Exception('invalid_request');
}

/** @var ImsLtiTool $tool */
$tool = Database::getManager()
->getRepository('ChamiloPluginBundle:ImsLti\ImsLtiTool')
->findOneBy(['clientId' => $claims['sub']]);

if (!$tool || empty($tool->publicKey)) {
throw new Exception('invalid_client');
}

return $tool;
}

/**
* Validate the request' scope. Return the allowed scopes in services.
*
* @param string $scope
* @param ImsLtiTool $tool
*
* @throws Exception
*
* @return array
*/
public function validateScope($scope, ImsLtiTool $tool)
{
if (empty($scope)) {
throw new Exception('invalid_request');
}

$services = ImsLti::getAdvantageServices($tool);

$requested = explode(' ', $scope);
$allowed = [];

/** @var LtiAdvantageService $service */
foreach ($services as $service) {
$allowed = array_merge($allowed, $service->getAllowedScopes());
}

$intersect = array_intersect($requested, $allowed);

if (empty($intersect)) {
throw new Exception('invalid_scope');
}

return $intersect;
}
}
35 changes: 35 additions & 0 deletions plugin/ims_lti/src/Service/LtiAdvantageService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
/* For licensing terms, see /license.txt */

use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool;

/**
* Class LtiAdvantageService.
*/
abstract class LtiAdvantageService
{
const AGS_SIMPLE = 'simple';
const AGS_FULL = 'full';

/**
* @var ImsLtiTool
*/
protected $tool;

/**
* @param ImsLtiTool $tool
*
* @return LtiAdvantageService
*/
public function setTool(ImsLtiTool $tool)
{
$this->tool = $tool;

return $this;
}

/**
* @return array
*/
abstract public function getAllowedScopes();
}
Loading

0 comments on commit 2ec596b

Please sign in to comment.