Skip to content

Commit

Permalink
add list of allow client for introspection endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
jdeniau committed Aug 22, 2018
1 parent 53e9199 commit 3306c81
Show file tree
Hide file tree
Showing 6 changed files with 167 additions and 7 deletions.
60 changes: 55 additions & 5 deletions Controller/IntrospectionController.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,19 @@

namespace FOS\OAuthServerBundle\Controller;

use FOS\OAuthServerBundle\Form\Model\Introspect;
use FOS\OAuthServerBundle\Form\Type\IntrospectionFormType;
use FOS\OAuthServerBundle\Model\AccessTokenInterface;
use FOS\OAuthServerBundle\Model\RefreshTokenInterface;
use FOS\OAuthServerBundle\Model\TokenInterface;
use FOS\OAuthServerBundle\Model\TokenManagerInterface;
use FOS\OAuthServerBundle\Security\Authentication\Token\OAuthToken;
use Symfony\Component\Form\FormFactory;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

class IntrospectionController
{
Expand All @@ -38,21 +44,47 @@ class IntrospectionController
*/
private $refreshTokenManager;

/**
* @var FormFactory
*/
private $formFactory;

/**
* @var array
*/
private $allowedIntrospectionClients;

public function __construct(
TokenStorageInterface $tokenStorage,
TokenManagerInterface $accessTokenManager,
TokenManagerInterface $refreshTokenManager
TokenManagerInterface $refreshTokenManager,
FormFactory $formFactory,
array $allowedIntrospectionClients
) {
$this->tokenStorage = $tokenStorage;
$this->accessTokenManager = $accessTokenManager;
$this->refreshTokenManager = $refreshTokenManager;
$this->formFactory = $formFactory;
$this->allowedIntrospectionClients = $allowedIntrospectionClients;
}

public function introspectAction(Request $request): JsonResponse
{
// $clientToken = $this->tokenStorage->getToken(); → use in security
$clientToken = $this->tokenStorage->getToken(); // → use in security

if (!$clientToken instanceof OAuthToken) {
throw new AccessDeniedException('The introspect endpoint must be behind a secure firewall.');
}

// TODO security for this endpoint. Probably in the README documentation
$callerToken = $this->accessTokenManager->findTokenByToken($clientToken->getToken());

if (!$callerToken) {
throw new AccessDeniedException('The access token must have a valid token.');
}

if (!in_array($callerToken->getClientId(), $this->allowedIntrospectionClients)) {
throw new AccessDeniedException('This access token is not autorised to do introspection.');
}

$token = $this->getToken($request);

Expand All @@ -79,8 +111,9 @@ public function introspectAction(Request $request): JsonResponse
*/
private function getToken(Request $request)
{
$tokenTypeHint = $request->request->get('token_type_hint'); // TODO move in a form type ? can be `access_token`, `refresh_token` See https://tools.ietf.org/html/rfc7009#section-4.1.2
$tokenString = $request->request->get('token'); // TODO move in a form type ?
$formData = $this->processIntrospectionForm($request);
$tokenString = $formData->token;
$tokenTypeHint = $formData->token_type_hint;

$tokenManagerList = [];
if (!$tokenTypeHint || 'access_token' === $tokenTypeHint) {
Expand Down Expand Up @@ -125,4 +158,21 @@ private function getUsername(TokenInterface $token)

return $user->getUserName();
}

private function processIntrospectionForm(Request $request): Introspect
{
$formData = new Introspect();
$form = $this->formFactory->create(IntrospectionFormType::class, $formData);
$form->handleRequest($request);

if (!$form->isSubmitted() || !$form->isValid()) {
$errors = $form->getErrors();
if (count($errors) > 0) {
throw new BadRequestHttpException((string) $errors);
} else {
throw new BadRequestHttpException('Introspection endpoint needs to have at least a "token" form parameter');
}
}
return $form->getData();
}
}
21 changes: 21 additions & 0 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public function getConfigTreeBuilder()
$this->addAuthorizeSection($rootNode);
$this->addServiceSection($rootNode);
$this->addTemplateSection($rootNode);
$this->addIntrospectionSection($rootNode);

return $treeBuilder;
}
Expand Down Expand Up @@ -151,4 +152,24 @@ private function addTemplateSection(ArrayNodeDefinition $node)
->end()
;
}

private function addIntrospectionSection(ArrayNodeDefinition $node)
{
$node
->addDefaultsIfNotSet()
->children()
->arrayNode('introspection')
->addDefaultsIfNotSet()
->children()
->arrayNode('allowed_clients')
->useAttributeAsKey('key')
->treatNullLike([])
->prototype('variable')->end()
->end()
->end()
->end()
->end()
->end()
;
}
}
7 changes: 5 additions & 2 deletions DependencyInjection/FOSOAuthServerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ public function load(array $configs, ContainerBuilder $container)
$authorizeFormDefinition->setFactory([new Reference('form.factory'), 'createNamed']);
}

$this->loadIntrospection($loader);
$this->loadIntrospection($config, $container, $loader);
}

/**
Expand Down Expand Up @@ -144,9 +144,12 @@ protected function remapParametersNamespaces(array $config, ContainerBuilder $co
}
}

protected function loadIntrospection(XmlFileLoader $loader)
protected function loadIntrospection(array $config, ContainerBuilder $container, XmlFileLoader $loader)
{
$loader->load('introspection.xml');

$allowedClients = $config['introspection']['allowed_clients'];
$container->setParameter('fos_oauth_server.introspection.allowed_clients', $allowedClients);
}

protected function loadAuthorize(array $config, ContainerBuilder $container, XmlFileLoader $loader)
Expand Down
30 changes: 30 additions & 0 deletions Form/Model/Introspect.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

/*
* This file is part of the FOSOAuthServerBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\OAuthServerBundle\Form\Model;

use Symfony\Component\Validator\Constraints as Assert;

class Introspect
{
/**
* @var string
* @Assert\NotBlank()
*/
public $token;

/**
* @var string
*/
public $token_type_hint;
}
54 changes: 54 additions & 0 deletions Form/Type/IntrospectionFormType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

declare(strict_types=1);

/*
* This file is part of the FOSOAuthServerBundle package.
*
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace FOS\OAuthServerBundle\Form\Type;

use FOS\OAuthServerBundle\Form\Model\Introspect;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class IntrospectionFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('token', HiddenType::class);
$builder->add('token_type_hint', ChoiceType::class, [ // can be `access_token`, `refresh_token` See https://tools.ietf.org/html/rfc7009#section-4.1.2
'choices' => [
'access_token' => 'access_token',
'refresh_token' => 'refresh_token',
]
]);
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Introspect::class,
'csrf_protection' => false,
]);
}

/**
* @return string
*/
public function getBlockPrefix()
{
return '';
}
}
2 changes: 2 additions & 0 deletions Resources/config/introspection.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
<argument type="service" id="security.token_storage" />
<argument type="service" id="fos_oauth_server.access_token_manager" />
<argument type="service" id="fos_oauth_server.refresh_token_manager" />
<argument type="service" id="form.factory" />
<argument>%fos_oauth_server.introspection.allowed_clients%</argument>
</service>
</services>

Expand Down

0 comments on commit 3306c81

Please sign in to comment.