Skip to content

Commit

Permalink
Merge pull request #396 from oat-sa/feat/AYT-3400/launching-authoring…
Browse files Browse the repository at this point in the history
…-by-new-configurable-roles

Feat/ayt 3400/launching authoring by new configurable roles
  • Loading branch information
bartlomiejmarszal authored Jan 4, 2024
2 parents a5ff316 + 28b4f2b commit 6a9f63e
Show file tree
Hide file tree
Showing 11 changed files with 303 additions and 4 deletions.
13 changes: 12 additions & 1 deletion controller/AuthoringTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
use oat\taoLti\models\classes\LtiException;
use oat\taoLti\models\classes\LtiMessages\LtiErrorMessage;
use oat\taoLti\models\classes\LtiService;
use oat\taoLti\models\classes\Tool\Exception\WrongLtiRolesException;
use oat\taoLti\models\classes\Tool\Service\AuthoringLtiRoleService;
use oat\taoLti\models\classes\Tool\Validation\Lti1p3Validator;
use oat\taoLti\models\classes\user\UserService;
use Psr\Container\ContainerExceptionInterface;
Expand Down Expand Up @@ -79,6 +81,7 @@ protected function getValidatedLtiMessagePayload(): LtiMessagePayloadInterface
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
* @throws common_exception_Error
* @throws WrongLtiRolesException
*/
public function launch(): void
{
Expand All @@ -90,8 +93,11 @@ public function launch(): void
->addUser(
$ltiMessage->getUserIdentity()->getIdentifier(),
helpers_Random::generateString(UserService::PASSWORD_LENGTH),
new core_kernel_classes_Resource(current($ltiMessage->getRoles()))
new core_kernel_classes_Resource(
$this->getAuthoringRoleService()->getValidRole($ltiMessage->getRoles())
)
);

$this->getServiceLocator()
->getContainer()
->get(LtiService::class)
Expand Down Expand Up @@ -145,4 +151,9 @@ private function getLtiMessageOrRedirectToLogin(): LtiMessagePayloadInterface

return $message;
}

private function getAuthoringRoleService(): AuthoringLtiRoleService
{
return $this->getPsrContainer()->get(AuthoringLtiRoleService::class);
}
}
2 changes: 1 addition & 1 deletion install/ontology/ltiroles_membership.rdf
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@
<rdfs:label xml:lang="en-US"><![CDATA[LTI 1p3 Instructor]]></rdfs:label>
<rdfs:comment xml:lang="en-US"><![CDATA[The LTI 1p3 Context Instructor Role]]></rdfs:comment>
<generis:includesRole rdf:resource="http://www.tao.lu/Ontologies/TAOLTI.rdf#LtiBaseRole"/>
<generis:includesRole rdf:resource="http://www.tao.lu/Ontologies/TAO.rdf#DeliveryRole"/>
<generis:includesRole rdf:resource="http://purl.imsglobal.org/vocab/lis/v2/membership/ContentDeveloper#ContentDeveloper"/>
<generis:isSystem rdf:resource="http://www.tao.lu/Ontologies/generis.rdf#True"/>
</rdf:Description>
<rdf:Description rdf:about="http://purl.imsglobal.org/vocab/lis/v2/membership/Instructor#ExternalInstructor">
Expand Down
9 changes: 9 additions & 0 deletions install/ontology/ltiroles_person.rdf
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,13 @@
<generis:isSystem rdf:resource="http://www.tao.lu/Ontologies/generis.rdf#True"/>
</rdf:Description>

<rdf:Description rdf:about="http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator">
<rdf:type rdf:resource="http://www.tao.lu/Ontologies/TAOLTI.rdf#LTIRole"/>
<rdfs:label xml:lang="en-US"><![CDATA[LTI Institution Administrator (System)]]></rdfs:label>
<rdfs:comment xml:lang="en-US"><![CDATA[The LTI Institution Administrator Role]]></rdfs:comment>
<taolti:RoleURN><![CDATA[urn:lti:sysrole:ims/lis/Administrator]]></taolti:RoleURN>
<generis:includesRole rdf:resource="http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#Developer"/>
<generis:isSystem rdf:resource="http://www.tao.lu/Ontologies/generis.rdf#True"/>
</rdf:Description>

</rdf:RDF>
82 changes: 82 additions & 0 deletions migrations/Version202312051317263774_taoLti.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
<?php

declare(strict_types=1);

namespace oat\taoLti\migrations;

use core_kernel_classes_Resource;
use core_kernel_users_Cache;
use Doctrine\DBAL\Schema\Schema;
use oat\oatbox\reporting\Report;
use oat\tao\model\accessControl\func\AccessRule;
use oat\tao\model\accessControl\func\AclProxy;
use oat\tao\model\user\TaoRoles;
use oat\tao\scripts\tools\migrations\AbstractMigration;
use oat\tao\scripts\update\OntologyUpdater;
use oat\taoLti\models\classes\LtiRoles;

/**
* Auto-generated Migration: Please modify to your needs!
*
* phpcs:disable Squiz.Classes.ValidClassName
*/
final class Version202312051317263774_taoLti extends AbstractMigration
{
public function getDescription(): string
{
return 'Apply new http://purl.imsglobal.org/vocab/lis/v2/membership#Instructor and http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator permission for AuthoringTool';
}

public function up(Schema $schema): void
{
AclProxy::applyRule($this->getLaunchActionRule());
AclProxy::applyRule($this->getRunActionRule(LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR));
AclProxy::applyRule($this->getRunActionRule(LtiRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR));

$this->addReport(
Report::createInfo(
sprintf(
'Clearing the Generis cache for roles %s',
LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR,
)
)
);
core_kernel_users_Cache::removeIncludedRoles(
new core_kernel_classes_Resource(LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR)
);
core_kernel_users_Cache::removeIncludedRoles(
new core_kernel_classes_Resource(LtiRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR)
);

OntologyUpdater::syncModels();

$this->addReport(Report::createInfo('Apply new permission for AuthoringTool'));
}

public function down(Schema $schema): void
{
AclProxy::revokeRule($this->getLaunchActionRule());
AclProxy::revokeRule($this->getRunActionRule(LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR));
AclProxy::revokeRule($this->getRunActionRule(LtiRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR));

$this->addReport(Report::createInfo('Revoke CONTEXT_INSTRUCTOR, CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR permission for AuthoringTool'));
}

private function getLaunchActionRule(): AccessRule
{
return new AccessRule(
AccessRule::GRANT,
TaoRoles::ANONYMOUS,
['ext' => 'taoLti', 'mod' => 'AuthoringTool', 'act' => 'launch']
);
}

private function getRunActionRule(string $role): AccessRule
{
return new AccessRule(
AccessRule::GRANT,
$role,
['ext' => 'taoLti', 'mod' => 'AuthoringTool', 'act' => 'run']
);
}
}
2 changes: 1 addition & 1 deletion models/classes/LtiLaunchData.php
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ public function getReturnUrl()
* which is a value of any type other than a resource.
* @since 5.4.0
*/
public function jsonSerialize()
public function jsonSerialize(): array
{
return [
'variables' => array_map(
Expand Down
2 changes: 2 additions & 0 deletions models/classes/LtiRoles.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,6 @@ interface LtiRoles
public const CONTEXT_LTI1P3_ADMINISTRATOR_SUB_EXTERNAL_SYSTEM_ADMINISTRATOR = 'http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#ExternalSystemAdministrator';
public const CONTEXT_LTI1P3_ADMINISTRATOR_SUB_SUPPORT = 'http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#Support';
public const CONTEXT_LTI1P3_ADMINISTRATOR_SUB_SYSTEM_ADMINISTRATOR = 'http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#SystemAdministrator';

public const CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR = 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator';
}
21 changes: 21 additions & 0 deletions models/classes/ServiceProvider/LtiServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,15 @@
use oat\taoLti\models\classes\Client\LtiClientFactory;
use oat\taoLti\models\classes\LtiAgs\LtiAgsScoreService;
use oat\taoLti\models\classes\LtiAgs\LtiAgsScoreServiceInterface;
use oat\taoLti\models\classes\LtiRoles;
use oat\taoLti\models\classes\Platform\Repository\DefaultToolConfig;
use oat\taoLti\models\classes\Platform\Repository\Lti1p3RegistrationRepository;
use oat\taoLti\models\classes\Platform\Repository\Lti1p3RegistrationSnapshotRepository;
use oat\taoLti\models\classes\Platform\Repository\LtiPlatformFactory;
use oat\taoLti\models\classes\Platform\Service\UpdatePlatformRegistrationSnapshotListener;
use oat\taoLti\models\classes\Security\DataAccess\Repository\CachedPlatformKeyChainRepository;
use oat\taoLti\models\classes\Security\DataAccess\Repository\PlatformKeyChainRepository;
use oat\taoLti\models\classes\Tool\Service\AuthoringLtiRoleService;
use oat\taoLti\models\classes\Tool\Validation\AuthoringToolValidator;
use oat\taoLti\models\classes\Tool\Validation\Lti1p3Validator;
use Psr\Cache\CacheItemPoolInterface;
Expand All @@ -79,6 +81,16 @@ public function __invoke(ContainerConfigurator $configurator): void
$_ENV['LTI_DEFAULT_SCOPE'] ?? 'https://purl.imsglobal.org/spec/lti-bo/scope/basicoutcome'
);

$parameters->set(
'rolesAllowed',
[
LtiRoles::CONTEXT_LTI1P3_ADMINISTRATOR_SUB_DEVELOPER,
LtiRoles::CONTEXT_LTI1P3_CONTENT_DEVELOPER_SUB_CONTENT_DEVELOPER,
LTIRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR,
LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR
]
);

$services
->set(LtiClientFactory::class)
->args(
Expand Down Expand Up @@ -238,5 +250,14 @@ public function __invoke(ContainerConfigurator $configurator): void
service(AuthoringToolValidator::class),
]
);

$services
->set(AuthoringLtiRoleService::class, AuthoringLtiRoleService::class)
->public()
->args(
[
param('rolesAllowed')
]
);
}
}
34 changes: 34 additions & 0 deletions models/classes/Tool/Exception/WrongLtiRolesException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2023 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoLti\models\classes\Tool\Exception;

use Exception;
use Throwable;

class WrongLtiRolesException extends Exception
{
public function __construct(string $message = "Role not allowed", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
46 changes: 46 additions & 0 deletions models/classes/Tool/Service/AuthoringLtiRoleService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2023 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoLti\models\classes\Tool\Service;

use oat\taoLti\models\classes\Tool\Exception\WrongLtiRolesException;

class AuthoringLtiRoleService
{
public function __construct(array $roleAllowed)
{
$this->roleAllowed = $roleAllowed;
}

/**
* @throws WrongLtiRolesException
*/
public function getValidRole(array $roles): string
{
$commonRoles = array_intersect($roles, $this->roleAllowed);

if (empty($commonRoles)) {
throw new WrongLtiRolesException();
}
return current($commonRoles);
}
}
2 changes: 1 addition & 1 deletion models/classes/user/LtiUser.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ public function refresh()
// nothing to do
}

public function jsonSerialize()
public function jsonSerialize(): array
{
return [
self::USER_IDENTIFIER => $this->userUri,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; under version 2
* of the License (non-upgradable).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Copyright (c) 2023 (original work) Open Assessment Technologies SA;
*/

declare(strict_types=1);

namespace oat\taoLti\test\unit\models\classes\Tool\Service;

use oat\taoLti\models\classes\LtiRoles;
use oat\taoLti\models\classes\Tool\Exception\WrongLtiRolesException;
use oat\taoLti\models\classes\Tool\Service\AuthoringLtiRoleService;
use PHPUnit\Framework\TestCase;

class AuthoringLtiRoleServiceTest extends TestCase
{
public function setUp(): void
{
$this->subject = new AuthoringLtiRoleService(
[
LtiRoles::CONTEXT_LTI1P3_ADMINISTRATOR_SUB_DEVELOPER,
LtiRoles::CONTEXT_LTI1P3_CONTENT_DEVELOPER_SUB_CONTENT_DEVELOPER,
LTIRoles::CONTEXT_INSTITUTION_LTI1P3_ADMINISTRATOR,
LtiRoles::CONTEXT_LTI1P3_INSTRUCTOR
]
);
}

/**
* @dataProvider ltiMessageRolesProvider
*/
public function testValidRole(array $rolesProvided, string $expected): void
{
self::assertEquals($expected, $this->subject->getValidRole($rolesProvided));
}

/**
* @dataProvider invalidRolesProvider
* @throws WrongLtiRolesException
*/
public function testExpectException(array $roles): void
{
$this->expectException(WrongLtiRolesException::class);
$this->subject->getValidRole($roles);
}

public function invalidRolesProvider(): array
{
return [
'Empty array' => [
'roles' => [],
],
'UnsupportedRole' => [
'roles' => ['http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#Support']
]
];
}

public function ltiMessageRolesProvider(): array
{
return [
'When one valid roles' => [
'rolesProvided' => [
'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator',
'http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#Support'
],
'expected' => 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator'
],
'When more than one valid roles' => [
'rolesProvided' => [
'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator',
'http://purl.imsglobal.org/vocab/lis/v2/membership/Administrator#Support',
'http://purl.imsglobal.org/vocab/lis/v2/membership/ContentDeveloper#ContentDeveloper'
],
'expected' => 'http://purl.imsglobal.org/vocab/lis/v2/institution/person#Administrator'
]
];
}
}

0 comments on commit 6a9f63e

Please sign in to comment.