From eae6f671c7f3b4619717c88d0dd3aef9689f731e Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 8 Aug 2017 17:27:19 +0300 Subject: [PATCH 1/7] Use fork of oauth2-php --- composer.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index b5e1cb55..8f3e66f3 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "license": "MIT", "name": "authbucket/oauth2-symfony-bundle", "require": { - "authbucket/oauth2-php": "~5.0.0-alpha4", + "authbucket/oauth2-php": "dev-master as ~5.0-dev", "php": ">=5.5.9", "symfony/framework-bundle": "~3.2", "symfony/monolog-bundle": "~3.0", @@ -53,5 +53,11 @@ "symfony/symfony": "~3.2", "twig/extensions": "~1.0" }, - "type": "symfony-bundle" + "type": "symfony-bundle", + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/mcfedr/oauth2-php" + } + ] } From 59ae906b428e2b24787a469e410375463326e07e Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 8 Aug 2017 17:27:37 +0300 Subject: [PATCH 2/7] Pass user provider to resource provider --- src/DependencyInjection/AuthBucketOAuth2Extension.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/DependencyInjection/AuthBucketOAuth2Extension.php b/src/DependencyInjection/AuthBucketOAuth2Extension.php index a1879266..1e158fea 100644 --- a/src/DependencyInjection/AuthBucketOAuth2Extension.php +++ b/src/DependencyInjection/AuthBucketOAuth2Extension.php @@ -49,8 +49,11 @@ public function load(array $configs, ContainerBuilder $container) $userProvider = $config['user_provider'] ?: null; if ($userProvider) { + $userProviderReference = new Reference($userProvider); $container->getDefinition('authbucket_oauth2.grant_type_handler.factory') - ->replaceArgument(5, new Reference($userProvider)); + ->replaceArgument(5, $userProviderReference); + $container->getDefinition('security.authentication.provider.resource') + ->replaceArgument(5, $userProviderReference); } unset($config['user_provider']); From fc086f92c3a71b2f9b8ac73c642d0980650f6567 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Tue, 8 Aug 2017 17:28:38 +0300 Subject: [PATCH 3/7] Param with client token roles and default role --- src/DependencyInjection/Configuration.php | 3 +++ src/Resources/config/services.yml | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index af64327b..816e94ed 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -48,6 +48,9 @@ public function getConfigTreeBuilder() ->arrayNode('resource_type_handler') ->prototype('scalar')->end() ->end() + ->arrayNode('client_token_roles') + ->prototype('scalar')->end() + ->end() ->end(); return $treeBuilder; diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 5f561d40..73227075 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -17,6 +17,9 @@ parameters: model: AuthBucket\OAuth2\ResourceType\ModelResourceTypeHandler debug_endpoint: AuthBucket\OAuth2\ResourceType\DebugEndpointResourceTypeHandler + authbucket_oauth2.client_token_roles: + - ROLE_CLIENT_ID + services: authbucket_oauth2.exception_listener: class: AuthBucket\OAuth2\Symfony\Component\EventDispatcher\ExceptionListener @@ -90,6 +93,7 @@ services: - "@security.authentication.manager" - "@validator" - "@logger" + - "%authbucket_oauth2.client_token_roles%" security.authentication.provider.resource: class: AuthBucket\OAuth2\Symfony\Component\Security\Core\Authentication\Provider\ResourceProvider @@ -99,6 +103,7 @@ services: - ~ - ~ - ~ + - ~ security.authentication.listener.resource: class: AuthBucket\OAuth2\Symfony\Component\Security\Http\Firewall\ResourceListener From c6d8287625fa71cb2a9aa54709313c725e555ab6 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 10 Aug 2017 12:27:01 +0300 Subject: [PATCH 4/7] Param with resource token roles and default role --- src/DependencyInjection/Configuration.php | 3 +++ src/Resources/config/services.yml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 816e94ed..9eb080a3 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -51,6 +51,9 @@ public function getConfigTreeBuilder() ->arrayNode('client_token_roles') ->prototype('scalar')->end() ->end() + ->arrayNode('resource_token_roles') + ->prototype('scalar')->end() + ->end() ->end(); return $treeBuilder; diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 73227075..0a883319 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -20,6 +20,9 @@ parameters: authbucket_oauth2.client_token_roles: - ROLE_CLIENT_ID + authbucket_oauth2.resource_token_roles: + - ROLE_RESOURCE + services: authbucket_oauth2.exception_listener: class: AuthBucket\OAuth2\Symfony\Component\EventDispatcher\ExceptionListener @@ -114,3 +117,4 @@ services: - "@validator" - "@logger" - "@authbucket_oauth2.token_type_handler.factory" + - "%authbucket_oauth2.resource_token_roles%" From 5ff75e5d338ff3f6a3d347996901434a4e50ef58 Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 10 Aug 2017 12:32:29 +0300 Subject: [PATCH 5/7] Changed tests to use unique codes/tokens The server now deletes tokens once they have been used --- .../AuthorizationCodeGrantTypeHandlerTest.php | 8 +++++-- .../RefreshTokenGrantTypeHandlerTest.php | 5 +++- .../DataFixtures/ORM/CodeFixture.php | 24 +++++++++++++++++++ .../DataFixtures/ORM/RefreshTokenFixture.php | 12 ++++++++++ 4 files changed, 46 insertions(+), 3 deletions(-) diff --git a/tests/GrantType/AuthorizationCodeGrantTypeHandlerTest.php b/tests/GrantType/AuthorizationCodeGrantTypeHandlerTest.php index 1511f385..6d3fbef5 100644 --- a/tests/GrantType/AuthorizationCodeGrantTypeHandlerTest.php +++ b/tests/GrantType/AuthorizationCodeGrantTypeHandlerTest.php @@ -145,9 +145,13 @@ public function testGoodAuthCode() $crawler = $client->request('POST', '/api/oauth2/token', $parameters, [], $server); $this->assertNotNull(json_decode($client->getResponse()->getContent())); + } + + public function testGoodAuthCodePostClient() + { $parameters = [ 'grant_type' => 'authorization_code', - 'code' => 'f0c68d250bcc729eb780a235371a9a55', + 'code' => 'f0c68d250bcc729eb780a235371a9a56', 'redirect_uri' => 'http://democlient2.com/redirect_uri', 'client_id' => 'http://democlient2.com/', 'client_secret' => 'demosecret2', @@ -164,7 +168,7 @@ public function testGoodAuthCodeNoPassedRedirectUri() { $parameters = [ 'grant_type' => 'authorization_code', - 'code' => 'f0c68d250bcc729eb780a235371a9a55', + 'code' => 'f0c68d250bcc729eb780a235371a9a57', 'client_id' => 'http://democlient2.com/', 'client_secret' => 'demosecret2', 'state' => 'f0c68d250bcc729eb780a235371a9a55', diff --git a/tests/GrantType/RefreshTokenGrantTypeHandlerTest.php b/tests/GrantType/RefreshTokenGrantTypeHandlerTest.php index fac1cc7a..157da114 100644 --- a/tests/GrantType/RefreshTokenGrantTypeHandlerTest.php +++ b/tests/GrantType/RefreshTokenGrantTypeHandlerTest.php @@ -163,10 +163,13 @@ public function testGoodRefreshToken() $crawler = $client->request('POST', '/api/oauth2/token', $parameters, [], $server); $this->assertSame(200, $client->getResponse()->getStatusCode()); $this->assertNotNull(json_decode($client->getResponse()->getContent())); + } + public function testGoodRefreshTokenHttpClientAuth() + { $parameters = [ 'grant_type' => 'refresh_token', - 'refresh_token' => '288b5ea8e75d2b24368a79ed5ed9593b', + 'refresh_token' => '288b5ea8e75d2b24368a79ed5ed9593c', ]; $server = [ 'PHP_AUTH_USER' => 'http://democlient3.com/', diff --git a/tests/TestBundle/DataFixtures/ORM/CodeFixture.php b/tests/TestBundle/DataFixtures/ORM/CodeFixture.php index 7c1db2d2..2464707a 100644 --- a/tests/TestBundle/DataFixtures/ORM/CodeFixture.php +++ b/tests/TestBundle/DataFixtures/ORM/CodeFixture.php @@ -31,6 +31,30 @@ public function load(ObjectManager $manager) ]); $manager->persist($model); + $model = new Code(); + $model->setCode('f0c68d250bcc729eb780a235371a9a56') + ->setClientId('http://democlient2.com/') + ->setUsername('demousername2') + ->setRedirectUri('http://democlient2.com/redirect_uri') + ->setExpires(new \DateTime('+10 minutes')) + ->setScope([ + 'demoscope1', + 'demoscope2', + ]); + $manager->persist($model); + + $model = new Code(); + $model->setCode('f0c68d250bcc729eb780a235371a9a57') + ->setClientId('http://democlient2.com/') + ->setUsername('demousername2') + ->setRedirectUri('http://democlient2.com/redirect_uri') + ->setExpires(new \DateTime('+10 minutes')) + ->setScope([ + 'demoscope1', + 'demoscope2', + ]); + $manager->persist($model); + $model = new Code(); $model->setCode('1e5aa97ddaf4b0228dfb4223010d4417') ->setClientId('http://democlient1.com/') diff --git a/tests/TestBundle/DataFixtures/ORM/RefreshTokenFixture.php b/tests/TestBundle/DataFixtures/ORM/RefreshTokenFixture.php index eaa9c434..2658a365 100644 --- a/tests/TestBundle/DataFixtures/ORM/RefreshTokenFixture.php +++ b/tests/TestBundle/DataFixtures/ORM/RefreshTokenFixture.php @@ -52,6 +52,18 @@ public function load(ObjectManager $manager) ]); $manager->persist($model); + $model = new RefreshToken(); + $model->setRefreshToken('288b5ea8e75d2b24368a79ed5ed9593c') + ->setClientId('http://democlient3.com/') + ->setUsername('demousername3') + ->setExpires(new \DateTime('+1 days')) + ->setScope([ + 'demoscope1', + 'demoscope2', + 'demoscope3', + ]); + $manager->persist($model); + $manager->flush(); } } From 2fd0eca5de0d11ca970cebc8c138f3f0a5b5ec8b Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 10 Aug 2017 12:32:57 +0300 Subject: [PATCH 6/7] Setup entry points for firewalls to correctly return 401 --- .../Security/Factory/ResourceFactory.php | 9 +++++++++ .../Security/Factory/TokenFactory.php | 9 +++++++++ tests/Controller/OAuth2ControllerTest.php | 13 +++++++++++++ tests/TokenType/BearerTokenTypeHandlerTest.php | 4 ++-- 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/DependencyInjection/Security/Factory/ResourceFactory.php b/src/DependencyInjection/Security/Factory/ResourceFactory.php index 6906b708..a1375a7a 100644 --- a/src/DependencyInjection/Security/Factory/ResourceFactory.php +++ b/src/DependencyInjection/Security/Factory/ResourceFactory.php @@ -11,9 +11,11 @@ namespace AuthBucket\Bundle\OAuth2Bundle\DependencyInjection\Security\Factory; +use AuthBucket\OAuth2\Symfony\Component\Security\Http\EntryPoint\ResourceAuthenticationEntryPoint; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; class ResourceFactory implements SecurityFactoryInterface @@ -38,6 +40,13 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider, $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.resource')) ->replaceArgument(0, $id); + if (!$defaultEntryPoint) { + $entryPointId = 'security.authentication.entrypoint.token.'.$id; + $container->setDefinition($entryPointId, new Definition(ResourceAuthenticationEntryPoint::class)); + + $defaultEntryPoint = $entryPointId; + } + return [$providerId, $listenerId, $defaultEntryPoint]; } diff --git a/src/DependencyInjection/Security/Factory/TokenFactory.php b/src/DependencyInjection/Security/Factory/TokenFactory.php index 6aa12de7..5cde7ab9 100644 --- a/src/DependencyInjection/Security/Factory/TokenFactory.php +++ b/src/DependencyInjection/Security/Factory/TokenFactory.php @@ -11,9 +11,11 @@ namespace AuthBucket\Bundle\OAuth2Bundle\DependencyInjection\Security\Factory; +use AuthBucket\OAuth2\Symfony\Component\Security\Http\EntryPoint\TokenAuthenticationEntryPoint; use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; use Symfony\Component\Config\Definition\Builder\NodeDefinition; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\DefinitionDecorator; class TokenFactory implements SecurityFactoryInterface @@ -28,6 +30,13 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider, $container->setDefinition($listenerId, new DefinitionDecorator('security.authentication.listener.token')) ->replaceArgument(0, $id); + if (!$defaultEntryPoint) { + $entryPointId = 'security.authentication.entrypoint.token.'.$id; + $container->setDefinition($entryPointId, new Definition(TokenAuthenticationEntryPoint::class)); + + $defaultEntryPoint = $entryPointId; + } + return [$providerId, $listenerId, $defaultEntryPoint]; } diff --git a/tests/Controller/OAuth2ControllerTest.php b/tests/Controller/OAuth2ControllerTest.php index 931edd64..d24e4219 100644 --- a/tests/Controller/OAuth2ControllerTest.php +++ b/tests/Controller/OAuth2ControllerTest.php @@ -36,6 +36,19 @@ public function testExceptionNoResponseType() $this->assertSame('invalid_request', $tokenResponse['error']); } + public function testExceptionNotLoggedIn() + { + $parameters = [ + 'client_id' => '1234', + ]; + $server = [ + + ]; + $client = $this->createClient(); + $crawler = $client->request('GET', '/api/oauth2/authorize', $parameters, [], $server); + $this->assertSame(401, $client->getResponse()->getStatusCode()); + } + public function testErrorBadResponseType() { $parameters = [ diff --git a/tests/TokenType/BearerTokenTypeHandlerTest.php b/tests/TokenType/BearerTokenTypeHandlerTest.php index 0c2daade..b85fa304 100644 --- a/tests/TokenType/BearerTokenTypeHandlerTest.php +++ b/tests/TokenType/BearerTokenTypeHandlerTest.php @@ -22,7 +22,7 @@ public function testExceptionNoToken() $server = []; $client = $this->createClient(); $crawler = $client->request('GET', '/api/oauth2/debug', $parameters, [], $server); - $this->assertSame(400, $client->getResponse()->getStatusCode()); + $this->assertSame(401, $client->getResponse()->getStatusCode()); $this->assertNotNull(json_decode($client->getResponse()->getContent())); $tokenResponse = json_decode($client->getResponse()->getContent(), true); $this->assertSame('invalid_request', $tokenResponse['error']); @@ -38,7 +38,7 @@ public function testExceptionDuplicateToken() ]; $client = $this->createClient(); $crawler = $client->request('GET', '/api/oauth2/debug', $parameters, [], $server); - $this->assertSame(400, $client->getResponse()->getStatusCode()); + $this->assertSame(401, $client->getResponse()->getStatusCode()); $this->assertNotNull(json_decode($client->getResponse()->getContent())); $tokenResponse = json_decode($client->getResponse()->getContent(), true); $this->assertSame('invalid_request', $tokenResponse['error']); From bff5c313cd0319adf7f22b3d4fb01257c56ae8ef Mon Sep 17 00:00:00 2001 From: Fred Cox Date: Thu, 10 Aug 2017 17:11:36 +0300 Subject: [PATCH 7/7] Add new grantType to Authorize --- src/Entity/Authorize.php | 31 +++++++++++++++++++ .../DataFixtures/ORM/AuthorizeFixture.php | 13 ++++++++ 2 files changed, 44 insertions(+) diff --git a/src/Entity/Authorize.php b/src/Entity/Authorize.php index 171d0463..2009b8b0 100644 --- a/src/Entity/Authorize.php +++ b/src/Entity/Authorize.php @@ -42,6 +42,13 @@ abstract class Authorize implements AuthorizeInterface */ protected $scope; + /** + * @var array + * + * @ORM\Column(name="grant_type", type="array") + */ + protected $grantType; + /** * Set client_id. * @@ -113,4 +120,28 @@ public function getScope() { return $this->scope; } + + /** + * Set grant type. + * + * @param array $grantType + * + * @return Authorize + */ + public function setGrantType($grantType) + { + $this->grantType = $grantType; + + return $this; + } + + /** + * Get grant type. + * + * @return array + */ + public function getGrantType() + { + return $this->grantType; + } } diff --git a/tests/TestBundle/DataFixtures/ORM/AuthorizeFixture.php b/tests/TestBundle/DataFixtures/ORM/AuthorizeFixture.php index 289aed71..b602d807 100644 --- a/tests/TestBundle/DataFixtures/ORM/AuthorizeFixture.php +++ b/tests/TestBundle/DataFixtures/ORM/AuthorizeFixture.php @@ -77,6 +77,11 @@ public function load(ObjectManager $manager) ->setUsername('demousername1') ->setScope([ 'demoscope1', + ]) + ->setGrantType([ + 'authorization_code', + 'implicit', + 'password', ]); $manager->persist($model); @@ -96,6 +101,11 @@ public function load(ObjectManager $manager) 'demoscope1', 'demoscope2', 'demoscope3', + ]) + ->setGrantType([ + 'authorization_code', + 'implicit', + 'password', ]); $manager->persist($model); @@ -106,6 +116,9 @@ public function load(ObjectManager $manager) 'demoscope1', 'demoscope2', 'demoscope3', + ]) + ->setGrantType([ + 'client_credentials', ]); $manager->persist($model);