parent
6effdeaf4d
commit
2ec596b983
@ -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; |
||||
} |
||||
} |
||||
@ -0,0 +1,5 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
require_once __DIR__.'/../../main/inc/global.inc.php'; |
||||
|
||||
@ -0,0 +1,5 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
require_once __DIR__.'/../../main/inc/global.inc.php'; |
||||
|
||||
@ -0,0 +1,5 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
require_once __DIR__.'/../../main/inc/global.inc.php'; |
||||
|
||||
@ -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; |
||||
} |
||||
} |
||||
@ -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(); |
||||
} |
||||
@ -0,0 +1,29 @@ |
||||
<?php |
||||
/* For licensing terms, see /license.txt */ |
||||
|
||||
use Chamilo\PluginBundle\Entity\ImsLti\ImsLtiTool; |
||||
|
||||
class LtiAssignmentGradesService extends LtiAdvantageService |
||||
{ |
||||
const SCOPE_LINE_ITEM = 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem'; |
||||
const SCOPE_LINE_ITEM_READ = 'https://purl.imsglobal.org/spec/lti-ags/scope/lineitem.readonly'; |
||||
const SCOPE_RESULT_READ = 'https://purl.imsglobal.org/spec/lti-ags/scope/result.readonly'; |
||||
const SCOPE_SCORE = 'https://purl.imsglobal.org/spec/lti-ags/scope/score'; |
||||
|
||||
public function getAllowedScopes() |
||||
{ |
||||
$scopes = [ |
||||
self::SCOPE_LINE_ITEM_READ, |
||||
self::SCOPE_RESULT_READ, |
||||
self::SCOPE_SCORE, |
||||
]; |
||||
|
||||
$toolServices = $this->tool->getAdvantageServices(); |
||||
|
||||
if (self::AGS_FULL === $toolServices['ags']) { |
||||
$scopes[] = self::SCOPE_LINE_ITEM; |
||||
} |
||||
|
||||
return $scopes; |
||||
} |
||||
} |
||||
Loading…
Reference in new issue