Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 1 addition & 64 deletions DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,48 +79,9 @@ private function createAuthorizationServerNode(): NodeDefinition
->cannotBeEmpty()
->defaultValue('P1M')
->end()

// @TODO Remove in v4 start

->scalarNode('auth_code_ttl')
->info("How long the issued authorization code should be valid for.\nThe value should be a valid interval: http://php.net/manual/en/dateinterval.construct.php#refsect1-dateinterval.construct-parameters")
->cannotBeEmpty()
->setDeprecated('"%path%.%node%" is deprecated, use "%path%.grant_types.authorization_code.auth_code_ttl" instead.')
->beforeNormalization()
->ifNull()
->thenUnset()
->end()
->end()
->booleanNode('require_code_challenge_for_public_clients')
->info('Whether to require code challenge for public clients for the authorization code grant.')
->setDeprecated('"%path%.%node%" is deprecated, use "%path%.grant_types.authorization_code.require_code_challenge_for_public_clients" instead.')
->beforeNormalization()
->ifNull()
->thenUnset()
->end()
->end()
->end()
;

foreach (OAuth2Grants::ALL as $grantType => $grantTypeName) {
$oldGrantType = 'authorization_code' === $grantType ? 'auth_code' : $grantType;

$node
->children()
->booleanNode(sprintf('enable_%s_grant', $oldGrantType))
->info(sprintf('Whether to enable the %s grant.', $grantTypeName))
->setDeprecated(sprintf('"%%path%%.%%node%%" is deprecated, use "%%path%%.grant_types.%s.enable" instead.', $grantType))
->beforeNormalization()
->ifNull()
->thenUnset()
->end()
->end()
->end()
;
}

// @TODO Remove in v4 end

$node->append($this->createAuthorizationServerGrantTypesNode());

$node
Expand All @@ -134,33 +95,9 @@ private function createAuthorizationServerNode(): NodeDefinition
if (isset($grantTypesWithRefreshToken[$grantType])) {
$grantTypeConfig['refresh_token_ttl'] = $grantTypeConfig['refresh_token_ttl'] ?? $v['refresh_token_ttl'];
}

// @TODO Remove in v4 start
$oldGrantType = 'authorization_code' === $grantType ? 'auth_code' : $grantType;

$grantTypeConfig['enable'] = $v[sprintf('enable_%s_grant', $oldGrantType)] ?? $grantTypeConfig['enable'];

if ('authorization_code' === $grantType) {
$grantTypeConfig['auth_code_ttl'] = $v['auth_code_ttl'] ?? $grantTypeConfig['auth_code_ttl'];
$grantTypeConfig['require_code_challenge_for_public_clients'] = $v['require_code_challenge_for_public_clients']
?? $grantTypeConfig['require_code_challenge_for_public_clients'];
}
// @TODO Remove in v4 end
}

unset(
$v['access_token_ttl'],
$v['refresh_token_ttl'],
// @TODO Remove in v4 start
$v['enable_auth_code_grant'],
$v['enable_client_credentials_grant'],
$v['enable_implicit_grant'],
$v['enable_password_grant'],
$v['enable_refresh_token_grant'],
$v['auth_code_ttl'],
$v['require_code_challenge_for_public_clients']
// @TODO Remove in v4 end
);
unset($v['access_token_ttl'], $v['refresh_token_ttl']);

return $v;
})
Expand Down
52 changes: 52 additions & 0 deletions Event/AuthenticationFailureEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Event;

use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Contracts\EventDispatcher\Event;

/**
* @author Benoit VIGNAL <github@benoit-vignal.fr>
*/
class AuthenticationFailureEvent extends Event {
/**
* @var AuthenticationException
*/
protected $exception;

/**
* @var Response
*/
protected $response;

/**
* @param AuthenticationException $exception
* @param Response $response
*/
public function __construct(AuthenticationException $exception, Response $response) {
$this->exception = $exception;
$this->response = $response;
}

/**
* @return AuthenticationException
*/
public function getException(): AuthenticationException {
return $this->exception;
}

/**
* @return Response
*/
public function getResponse(): Response {
return $this->response;
}

/**
* @param Response $response
*/
public function setResponse(Response $response): void {
$this->response = $response;
}
}
4 changes: 2 additions & 2 deletions EventListener/ConvertExceptionToResponseListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\InsufficientScopesException;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\Oauth2AuthenticationFailedException;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\OAuth2AuthenticationFailedException;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
Expand All @@ -17,7 +17,7 @@ final class ConvertExceptionToResponseListener
public function onKernelException(ExceptionEvent $event): void
{
$exception = $event->getThrowable();
if ($exception instanceof InsufficientScopesException || $exception instanceof Oauth2AuthenticationFailedException) {
if ($exception instanceof InsufficientScopesException || $exception instanceof OAuth2AuthenticationFailedException) {
$event->setResponse(new Response($exception->getMessage(), $exception->getCode()));
}
}
Expand Down
13 changes: 10 additions & 3 deletions OAuth2Events.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,34 @@
final class OAuth2Events
{
/**
* The USER_RESOLVE event occurrs when the client requests a "password"
* The USER_RESOLVE event occurs when the client requests a "password"
* grant type from the authorization server.
*
* You should set a valid user here if applicable.
*/
public const USER_RESOLVE = 'trikoder.oauth2.user_resolve';

/**
* The SCOPE_RESOLVE event occurrs right before the user obtains their
* The SCOPE_RESOLVE event occurs right before the user obtains their
* valid access token.
*
* You could alter the access token's scope here.
*/
public const SCOPE_RESOLVE = 'trikoder.oauth2.scope_resolve';

/**
* The AUTHORIZATION_REQUEST_RESOLVE event occurrs right before the system
* The AUTHORIZATION_REQUEST_RESOLVE event occurs right before the system
* complete the authorization request.
*
* You could approve or deny the authorization request, or set the uri where
* must be redirected to resolve the authorization request.
*/
public const AUTHORIZATION_REQUEST_RESOLVE = 'trikoder.oauth2.authorization_request_resolve';

/**
* The AUTHENTICATION_FAILURE event occurs when the oauth token wasn't found
*
* You can set a custom error message in the response body
*/
public const AUTHENTICATION_FAILURE = 'trikoder.oauth2.autentication_failure';
}
10 changes: 0 additions & 10 deletions OAuth2Grants.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,4 @@ final class OAuth2Grants
self::PASSWORD => 'password',
self::REFRESH_TOKEN => 'refresh token',
];

/**
* @deprecated Will be removed in v4, use {@see OAuth2Grants::ALL} instead
*
* @TODO Remove in v4.
*/
public static function has(string $grant): bool
{
return isset(self::ALL[$grant]);
}
}
24 changes: 1 addition & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Trikoder OAuth 2 Bundle

[![Build Status](https://github.com/trikoder/oauth2-bundle/workflows/Tests/badge.svg?branch=v3.x)](https://github.com/trikoder/oauth2-bundle/actions)
[![Build Status](https://github.com/trikoder/oauth2-bundle/workflows/Tests/badge.svg?branch=master)](https://github.com/trikoder/oauth2-bundle/actions)
[![Latest Stable Version](https://poser.pugx.org/trikoder/oauth2-bundle/v/stable)](https://packagist.org/packages/trikoder/oauth2-bundle)
[![License](https://poser.pugx.org/trikoder/oauth2-bundle/license)](https://packagist.org/packages/trikoder/oauth2-bundle)
[![Code coverage](https://codecov.io/gh/trikoder/oauth2-bundle/branch/master/graph/badge.svg)](https://codecov.io/gh/trikoder/oauth2-bundle)
Expand Down Expand Up @@ -68,28 +68,6 @@ This package is currently in the active development.
# The value should be a valid interval: http://php.net/manual/en/dateinterval.construct.php#refsect1-dateinterval.construct-parameters
refresh_token_ttl: P1M

# How long the issued authorization code should be valid for.
# The value should be a valid interval: http://php.net/manual/en/dateinterval.construct.php#refsect1-dateinterval.construct-parameters
auth_code_ttl: ~ # Deprecated ("trikoder_oauth2.authorization_server.auth_code_ttl" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.authorization_code.auth_code_ttl" instead.)

# Whether to require code challenge for public clients for the authorization code grant.
require_code_challenge_for_public_clients: ~ # Deprecated ("trikoder_oauth2.authorization_server.require_code_challenge_for_public_clients" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.authorization_code.require_code_challenge_for_public_clients" instead.)

# Whether to enable the authorization code grant.
enable_auth_code_grant: ~ # Deprecated ("trikoder_oauth2.authorization_server.enable_auth_code_grant" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.authorization_code.enable" instead.)

# Whether to enable the client credentials grant.
enable_client_credentials_grant: ~ # Deprecated ("trikoder_oauth2.authorization_server.enable_client_credentials_grant" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.client_credentials.enable" instead.)

# Whether to enable the implicit grant.
enable_implicit_grant: ~ # Deprecated ("trikoder_oauth2.authorization_server.enable_implicit_grant" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.implicit.enable" instead.)

# Whether to enable the password grant.
enable_password_grant: ~ # Deprecated ("trikoder_oauth2.authorization_server.enable_password_grant" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.password.enable" instead.)

# Whether to enable the refresh token grant.
enable_refresh_token_grant: ~ # Deprecated ("trikoder_oauth2.authorization_server.enable_refresh_token_grant" is deprecated, use "trikoder_oauth2.authorization_server.grant_types.refresh_token.enable" instead.)

# Enable and configure grant types.
grant_types:
authorization_code:
Expand Down
1 change: 1 addition & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<argument type="service" id="security.token_storage" />
<argument type="service" id="security.authentication.manager" />
<argument type="service" id="sensio_framework_extra.psr7.http_message_factory" />
<argument type="service" id="Symfony\Component\EventDispatcher\EventDispatcherInterface" />
<argument key="$oauth2TokenFactory" type="service" id="Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory" />
</service>
<service id="trikoder.oauth2.security.firewall.oauth2_listener" alias="Trikoder\Bundle\OAuth2Bundle\Security\Firewall\OAuth2Listener">
Expand Down
19 changes: 19 additions & 0 deletions Security/Exception/OAuth2AuthenticationFailedException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types=1);

namespace Trikoder\Bundle\OAuth2Bundle\Security\Exception;

use Symfony\Component\Security\Core\Exception\AuthenticationException;

/**
* @author Tobias Nyholm <tobias.nyholm@gmail.com>
* @author Benoit VIGNAL <github@benoit-vignal.fr>
*/
class OAuth2AuthenticationFailedException extends AuthenticationException
{
/**
* {@inheritdoc}
*/
public function getMessageKey(): string {
return "OAuth Token not found";
}
}
18 changes: 0 additions & 18 deletions Security/Exception/Oauth2AuthenticationFailedException.php

This file was deleted.

24 changes: 22 additions & 2 deletions Security/Firewall/OAuth2Listener.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,19 @@
namespace Trikoder\Bundle\OAuth2Bundle\Security\Firewall;

use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Trikoder\Bundle\OAuth2Bundle\Event\AuthenticationFailureEvent;
use Trikoder\Bundle\OAuth2Bundle\OAuth2Events;
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2Token;
use Trikoder\Bundle\OAuth2Bundle\Security\Authentication\Token\OAuth2TokenFactory;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\InsufficientScopesException;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\Oauth2AuthenticationFailedException;
use Trikoder\Bundle\OAuth2Bundle\Security\Exception\OAuth2AuthenticationFailedException;

final class OAuth2Listener
{
Expand All @@ -37,6 +41,11 @@ final class OAuth2Listener
*/
private $oauth2TokenFactory;

/**
* @var EventDispatcherInterface
*/
private $eventDispatcher;

/**
* @var string
*/
Expand All @@ -46,12 +55,14 @@ public function __construct(
TokenStorageInterface $tokenStorage,
AuthenticationManagerInterface $authenticationManager,
HttpMessageFactoryInterface $httpMessageFactory,
EventDispatcherInterface $eventDispatcher,
OAuth2TokenFactory $oauth2TokenFactory,
string $providerKey
) {
$this->tokenStorage = $tokenStorage;
$this->authenticationManager = $authenticationManager;
$this->httpMessageFactory = $httpMessageFactory;
$this->eventDispatcher = $eventDispatcher;
$this->oauth2TokenFactory = $oauth2TokenFactory;
$this->providerKey = $providerKey;
}
Expand All @@ -68,7 +79,16 @@ public function __invoke(RequestEvent $event)
/** @var OAuth2Token $authenticatedToken */
$authenticatedToken = $this->authenticationManager->authenticate($this->oauth2TokenFactory->createOAuth2Token($request, null, $this->providerKey));
} catch (AuthenticationException $e) {
throw new Oauth2AuthenticationFailedException($e->getMessage(), 401, $e);
$exception = new OAuth2AuthenticationFailedException("OAuth Token not found", 0, $e);
$response = new Response($exception->getMessageKey(), Response::HTTP_UNAUTHORIZED);

$authenticationFailureEvent = new AuthenticationFailureEvent($exception, $response);
$this->eventDispatcher->dispatch($authenticationFailureEvent, OAuth2Events::AUTHENTICATION_FAILURE);

if ($response = $authenticationFailureEvent->getResponse()) {
$event->setResponse($response);
}
return;
}

if (!$this->isAccessToRouteGranted($event->getRequest(), $authenticatedToken)) {
Expand Down
Loading