Created
October 16, 2021 18:30
-
-
Save ekkinox/fdc90a51f73aed92f004becd81ddc5fa to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Security; | |
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Result\LaunchValidationResultInterface; | |
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\BadgeInterface; | |
class LtiBadge implements BadgeInterface | |
{ | |
/** @var LaunchValidationResultInterface */ | |
private $validationResult; | |
public function __construct(LaunchValidationResultInterface $validationResult) | |
{ | |
$this->validationResult = $validationResult; | |
} | |
public function getValidationResult(): LaunchValidationResultInterface | |
{ | |
return $this->validationResult; | |
} | |
public function isResolved(): bool | |
{ | |
return !$this->validationResult->hasError(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Security; | |
use OAT\Bundle\Lti1p3Bundle\Security\Authentication\Token\Message\LtiToolMessageSecurityToken; | |
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Tool\ToolLaunchValidatorInterface; | |
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; | |
use Symfony\Component\HttpFoundation\JsonResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; | |
use Symfony\Component\Security\Core\Exception\LogicException; | |
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; | |
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; | |
class LtiMessageAuthenticator extends AbstractAuthenticator | |
{ | |
/** @var ToolLaunchValidatorInterface */ | |
private $validator; | |
/** @var HttpMessageFactoryInterface */ | |
private $factory; | |
/** string[] */ | |
private $types; | |
public function __construct(ToolLaunchValidatorInterface $validator, HttpMessageFactoryInterface $factory, array $types = []) | |
{ | |
$this->validator = $validator; | |
$this->factory = $factory; | |
$this->types = $types; | |
} | |
public function supports(Request $request): ?bool | |
{ | |
return null !== $request->get('id_token'); | |
} | |
public function authenticate(Request $request): PassportInterface | |
{ | |
$validationResult = $this->validator->validatePlatformOriginatingLaunch( | |
$this->factory->createRequest($request) | |
); | |
if ($validationResult->hasError()) { | |
throw new CustomUserMessageAuthenticationException($validationResult->getError()); | |
} | |
$messageType = $validationResult->getPayload()->getMessageType(); | |
if (!empty($this->types) && !in_array($messageType, $this->types)) { | |
throw new BadRequestHttpException(sprintf('Invalid LTI message type %s', $messageType)); | |
} | |
return new LtiPassport(new LtiBadge($validationResult)); | |
} | |
public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface | |
{ | |
if (!$passport instanceof LtiPassport) { | |
throw new LogicException(sprintf('Provided passport must be a %s instance', LtiPassport::class)); | |
} | |
return new LtiToolMessageSecurityToken($passport->getLtiBadge()->getValidationResult()); | |
} | |
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response | |
{ | |
return null; | |
} | |
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response | |
{ | |
$data = [ | |
'message' => strtr($exception->getMessageKey(), $exception->getMessageData()) | |
]; | |
return new JsonResponse($data, Response::HTTP_UNAUTHORIZED); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Security; | |
use OAT\Library\Lti1p3Core\Exception\LtiException; | |
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Tool\ToolLaunchValidatorInterface; | |
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; | |
use Symfony\Component\HttpFoundation\JsonResponse; | |
use Symfony\Component\HttpFoundation\Request; | |
use Symfony\Component\HttpFoundation\Response; | |
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; | |
use Symfony\Component\Security\Core\Exception\AuthenticationException; | |
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException; | |
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator; | |
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; | |
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; | |
use Symfony\Component\Security\Http\Authenticator\Passport\PassportTrait; | |
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; | |
class LtiPassport implements PassportInterface | |
{ | |
use PassportTrait; | |
public function __construct(LtiBadge $ltiBadge) | |
{ | |
$this->addBadge($ltiBadge); | |
} | |
public function getLtiBadge(): ?LtiBadge | |
{ | |
return $this->getBadge(LtiBadge::class); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This program is free software; you can redistribute it and/or | |
* modify it under the terms of the GNU Lesser 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 Lesser General Public License for more details. | |
* | |
* You should have received a copy of the GNU Lesser 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) 2020 (original work) Open Assessment Technologies SA; | |
*/ | |
declare(strict_types=1); | |
namespace OAT\Bundle\Lti1p3Bundle\DependencyInjection\Security\Factory\Message; | |
use App\Security\LtiMessageAuthenticator; | |
use OAT\Bundle\Lti1p3Bundle\Security\Authentication\Provider\Message\LtiToolMessageAuthenticationProvider; | |
use OAT\Bundle\Lti1p3Bundle\Security\Firewall\Message\LtiToolMessageAuthenticationListener; | |
use OAT\Library\Lti1p3Core\Message\Launch\Validator\Tool\ToolLaunchValidatorInterface; | |
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface; | |
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\AuthenticatorFactoryInterface; | |
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; | |
use Symfony\Component\Config\Definition\Builder\NodeDefinition; | |
use Symfony\Component\DependencyInjection\ChildDefinition; | |
use Symfony\Component\DependencyInjection\ContainerBuilder; | |
use Symfony\Component\DependencyInjection\Definition; | |
use Symfony\Component\DependencyInjection\Reference; | |
class LtiToolMessageSecurityFactory implements SecurityFactoryInterface, AuthenticatorFactoryInterface | |
{ | |
public function getPosition(): string | |
{ | |
return 'pre_auth'; | |
} | |
public function getKey(): string | |
{ | |
return 'lti1p3_message_tool'; | |
} | |
public function create( | |
ContainerBuilder $container, | |
$id, | |
$config, | |
$userProvider, | |
$defaultEntryPoint = null | |
) { | |
$providerId = sprintf('security.authentication.provider.%s.%s', $this->getKey(), $id); | |
$providerDefinition = new Definition(LtiToolMessageAuthenticationProvider::class); | |
$providerDefinition | |
->setShared(false) | |
->setArguments( | |
[ | |
new Reference(ToolLaunchValidatorInterface::class), | |
$id, | |
$config['types'] ?? [] | |
] | |
); | |
$container->setDefinition($providerId, $providerDefinition); | |
$listenerId = sprintf('security.authentication.listener.%s.%s', $this->getKey(), $id); | |
$container->setDefinition($listenerId, new ChildDefinition(LtiToolMessageAuthenticationListener::class)); | |
return [$providerId, $listenerId, $defaultEntryPoint]; | |
} | |
public function createAuthenticator(ContainerBuilder $container, string $firewallName, array $config, string $userProviderId): string | |
{ | |
$authenticatorId = sprintf('security.authenticator.%s.%s', $this->getKey(), $firewallName); | |
$authenticatorDefinition = new Definition(LtiMessageAuthenticator::class); | |
$authenticatorDefinition | |
->setShared(false) | |
->setArguments( | |
[ | |
new Reference(ToolLaunchValidatorInterface::class), | |
new Reference(HttpMessageFactoryInterface::class), | |
$config['types'] ?? [] | |
] | |
); | |
$container->setDefinition($authenticatorId, $authenticatorDefinition); | |
return $authenticatorId; | |
} | |
public function addConfiguration(NodeDefinition $node): void | |
{ | |
$node->children()->arrayNode('types')->scalarPrototype()->end(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment