Skip to content

Commit c1084a1

Browse files
authored
Merge pull request #53 from robertpustulka/provider
Add AuthorizationServiceProviderInterface
2 parents 6a67086 + 7c4b682 commit c1084a1

File tree

4 files changed

+73
-77
lines changed

4 files changed

+73
-77
lines changed

docs/Middleware.md

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,37 @@ Authorization is applied to your application as a middleware. The
77
`applyScope` if necessary.
88
* Ensuring that authorization has been checked/bypassed in the request.
99

10-
To use the middleware, update the `middleware` hook of your `Application` with
11-
the following:
10+
To use the middleware implement `AuthorizationServiceProviderInterface` in your
11+
application class. Then pass your app instance into the middlware and add the
12+
middleware to the queue.
1213

13-
```php
14-
// Import the class.
15-
use Authorization\Middleware\AuthorizationMiddleware;
16-
17-
// inside your application's middleware hook.
18-
$middlewareQueue->add(new AuthorizationMiddleware($this));
19-
```
20-
21-
By passing your application instance into the middlware, it can invoke the
22-
``authorization`` hook method on your application which should return
23-
a configured `AuthorizationService`. A very simple example would be:
14+
A very simple example would be:
2415

2516
```php
2617
namespace App;
2718

2819
use Authorization\AuthorizationService;
20+
use Authorization\AuthorizationServiceProviderInterface;
21+
use Authorization\Middleware\AuthorizationMiddleware;
2922
use Authorization\Policy\OrmResolver;
3023
use Cake\Http\BaseApplication;
3124

32-
class Application extends BaseApplication
25+
class Application extends BaseApplication implements AuthorizationServiceProviderInterface
3326
{
34-
public function authorization($request)
27+
public function getAuthorizationService(ServerRequestInterface $request, ResponseInterface $response)
3528
{
3629
$resolver = new OrmResolver();
3730

3831
return new AuthorizationService($resolver);
3932
}
33+
34+
public function middleware($middlewareQueue)
35+
{
36+
// other middleware
37+
$middlewareQueue->add(new AuthorizationMiddleware($this));
38+
39+
return $middlewareQueue;
40+
}
4041
}
4142
```
4243

@@ -109,7 +110,7 @@ setup:
109110
// In your Application::middleware() method;
110111

111112
// Authorization
112-
$middleware->add(new AuthorizationMiddleware($this, [
113+
$middlewareQueue->add(new AuthorizationMiddleware($this, [
113114
'identityDecorator' => function ($auth, $user) {
114115
return $user->setAuthorization($auth);
115116
}
@@ -130,7 +131,7 @@ a helpful aid during development/testing. You can disable this behavior via an
130131
option:
131132

132133
```php
133-
$middlewareStack->add(new AuthorizationMiddleware($this, [
134+
$middlewareQueue->add(new AuthorizationMiddleware($this, [
134135
'requireAuthorizationCheck' => false
135136
]));
136137
```
@@ -157,7 +158,7 @@ Both redirect handlers share the same configuration options:
157158
For example:
158159

159160
```php
160-
$middlewareStack->add(new AuthorizationMiddleware($this, [
161+
$middlewareQueue->add(new AuthorizationMiddleware($this, [
161162
'unauthorizedHandler' => [
162163
'className' => 'Authorization.Redirect',
163164
'url' => '/users/login',
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
/**
3+
* CakePHP(tm) : Rapid Development Framework (https://cakephp.org)
4+
* Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
5+
*
6+
* Licensed under The MIT License
7+
* For full copyright and license information, please see the LICENSE.txt
8+
* Redistributions of files must retain the above copyright notice.
9+
*
10+
* @copyright Copyright (c) Cake Software Foundation, Inc. (https://cakefoundation.org)
11+
* @link https://cakephp.org CakePHP(tm) Project
12+
* @since 1.0.0
13+
* @license https://opensource.org/licenses/mit-license.php MIT License
14+
*/
15+
namespace Authorization;
16+
17+
use Psr\Http\Message\ResponseInterface;
18+
use Psr\Http\Message\ServerRequestInterface;
19+
20+
/**
21+
* This interface should be implemented by the authorization service provider.
22+
*/
23+
interface AuthorizationServiceProviderInterface
24+
{
25+
26+
/**
27+
* Returns authorization service instance.
28+
*
29+
* @param \Psr\Http\Message\ServerRequestInterface $request Request
30+
* @param \Psr\Http\Message\ResponseInterface $response Response
31+
* @return \Authorization\AuthorizationServiceInterface
32+
*/
33+
public function getAuthorizationService(ServerRequestInterface $request, ResponseInterface $response);
34+
}

src/Middleware/AuthorizationMiddleware.php

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
namespace Authorization\Middleware;
1616

1717
use Authorization\AuthorizationServiceInterface;
18+
use Authorization\AuthorizationServiceProviderInterface;
1819
use Authorization\Exception\AuthorizationRequiredException;
1920
use Authorization\Exception\Exception;
2021
use Authorization\IdentityDecorator;
2122
use Authorization\IdentityInterface;
2223
use Authorization\Middleware\UnauthorizedHandler\HandlerFactory;
23-
use Cake\Core\HttpApplicationInterface;
2424
use Cake\Core\InstanceConfigTrait;
2525
use InvalidArgumentException;
2626
use Psr\Http\Message\ResponseInterface;
@@ -60,23 +60,23 @@ class AuthorizationMiddleware
6060
/**
6161
* Authorization service or application instance.
6262
*
63-
* @var \Authorization\AuthorizationServiceInterface|\Cake\Core\HttpApplicationInterface
63+
* @var \Authorization\AuthorizationServiceInterface|\Authorization\AuthorizationServiceProviderInterface
6464
*/
6565
protected $subject;
6666

6767
/**
6868
* Constructor.
6969
*
70-
* @param \Authorization\AuthorizationServiceInterface|\Cake\Core\HttpApplicationInterface $subject Authorization service or application instance.
70+
* @param \Authorization\AuthorizationServiceInterface|\Authorization\AuthorizationServiceProviderInterface $subject Authorization service or provider instance.
7171
* @param array $config Config array.
7272
* @throws \InvalidArgumentException
7373
*/
7474
public function __construct($subject, array $config = [])
7575
{
76-
if (!$subject instanceof AuthorizationServiceInterface && !$subject instanceof HttpApplicationInterface) {
76+
if (!$subject instanceof AuthorizationServiceInterface && !$subject instanceof AuthorizationServiceProviderInterface) {
7777
$expected = implode('` or `', [
7878
AuthorizationServiceInterface::class,
79-
HttpApplicationInterface::class
79+
AuthorizationServiceProviderInterface::class
8080
]);
8181
$type = is_object($subject) ? get_class($subject) : gettype($subject);
8282
$message = sprintf('Subject must be an instance of `%s`, `%s` given.', $expected, $type);
@@ -152,22 +152,14 @@ protected function getHandler()
152152
*/
153153
protected function getAuthorizationService($request, $response)
154154
{
155-
if ($this->subject instanceof AuthorizationServiceInterface) {
156-
return $this->subject;
155+
$service = $this->subject;
156+
if ($this->subject instanceof AuthorizationServiceProviderInterface) {
157+
$service = $this->subject->getAuthorizationService($request, $response);
157158
}
158159

159-
$method = 'authorization';
160-
if (!method_exists($this->subject, $method)) {
161-
$message = sprintf('Method `%s` has not been defined in your `Application` class.', $method);
162-
throw new RuntimeException($message);
163-
}
164-
165-
$service = $this->subject->$method($request, $response);
166-
167160
if (!$service instanceof AuthorizationServiceInterface) {
168161
throw new RuntimeException(sprintf(
169-
'Invalid service returned from `%s` method. `%s` does not implement `%s`.',
170-
$method,
162+
'Invalid service returned from the provider. `%s` does not implement `%s`.',
171163
is_object($service) ? get_class($service) : gettype($service),
172164
AuthorizationServiceInterface::class
173165
));

tests/TestCase/Middleware/AuthorizationMiddlewareTest.php

Lines changed: 11 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
namespace Authorization\Test\TestCase\Middleware;
1616

1717
use Authorization\AuthorizationServiceInterface;
18+
use Authorization\AuthorizationServiceProviderInterface;
1819
use Authorization\Exception\AuthorizationRequiredException;
1920
use Authorization\Exception\Exception;
2021
use Authorization\IdentityDecorator;
2122
use Authorization\IdentityInterface;
2223
use Authorization\Middleware\AuthorizationMiddleware;
23-
use Cake\Core\HttpApplicationInterface;
2424
use Cake\Http\Response;
2525
use Cake\Http\ServerRequest;
2626
use Cake\TestSuite\TestCase;
@@ -78,13 +78,10 @@ public function testInvokeAuthorizationRequiredError()
7878
public function testInvokeApp()
7979
{
8080
$service = $this->createMock(AuthorizationServiceInterface::class);
81-
82-
$application = $this->getMockBuilder(HttpApplicationInterface::class)
83-
->setMethods(['authorization', 'middleware', 'routes', 'bootstrap', '__invoke'])
84-
->getMock();
85-
$application
81+
$provider = $this->createMock(AuthorizationServiceProviderInterface::class);
82+
$provider
8683
->expects($this->once())
87-
->method('authorization')
84+
->method('getAuthorizationService')
8885
->with(
8986
$this->isInstanceOf(ServerRequestInterface::class),
9087
$this->isInstanceOf(ResponseInterface::class)
@@ -97,7 +94,7 @@ public function testInvokeApp()
9794
return $request;
9895
};
9996

100-
$middleware = new AuthorizationMiddleware($application, ['requireAuthorizationCheck' => false]);
97+
$middleware = new AuthorizationMiddleware($provider, ['requireAuthorizationCheck' => false]);
10198

10299
$result = $middleware($request, $response, $next);
103100

@@ -106,40 +103,12 @@ public function testInvokeApp()
106103
$this->assertNull($result->getAttribute('identity'));
107104
}
108105

109-
public function testInvokeAppMissing()
110-
{
111-
$service = $this->createMock(AuthorizationServiceInterface::class);
112-
113-
$application = $this->getMockBuilder(HttpApplicationInterface::class)
114-
->setMethods(['middleware', 'routes', 'bootstrap', '__invoke'])
115-
->getMock();
116-
117-
$request = new ServerRequest();
118-
$response = new Response();
119-
$next = function ($request) {
120-
return $request;
121-
};
122-
123-
$middleware = new AuthorizationMiddleware($application, ['requireAuthorizationCheck' => false]);
124-
125-
$this->expectException(RuntimeException::class);
126-
$this->expectExceptionMessage('Method `authorization` has not been defined in your `Application` class.');
127-
128-
$result = $middleware($request, $response, $next);
129-
}
130-
131106
public function testInvokeAppInvalid()
132107
{
133-
$application = $this->getMockBuilder(HttpApplicationInterface::class)
134-
->setMethods(['middleware', 'routes', 'bootstrap', '__invoke'])
135-
->getMock();
136-
137-
$application = $this->getMockBuilder(HttpApplicationInterface::class)
138-
->setMethods(['authorization', 'middleware', 'routes', 'bootstrap', '__invoke'])
139-
->getMock();
140-
$application
108+
$provider = $this->createMock(AuthorizationServiceProviderInterface::class);
109+
$provider
141110
->expects($this->once())
142-
->method('authorization')
111+
->method('getAuthorizationService')
143112
->with(
144113
$this->isInstanceOf(ServerRequestInterface::class),
145114
$this->isInstanceOf(ResponseInterface::class)
@@ -152,11 +121,11 @@ public function testInvokeAppInvalid()
152121
return $request;
153122
};
154123

155-
$middleware = new AuthorizationMiddleware($application, ['requireAuthorizationCheck' => false]);
124+
$middleware = new AuthorizationMiddleware($provider, ['requireAuthorizationCheck' => false]);
156125

157126
$this->expectException(RuntimeException::class);
158127
$this->expectExceptionMessage(
159-
'Invalid service returned from `authorization` method. ' .
128+
'Invalid service returned from the provider. ' .
160129
'`stdClass` does not implement `Authorization\AuthorizationServiceInterface`.'
161130
);
162131

@@ -176,7 +145,7 @@ public function testInvokeInvalid()
176145
$this->expectException(InvalidArgumentException::class);
177146
$this->expectExceptionMessage(
178147
'Subject must be an instance of `Authorization\AuthorizationServiceInterface` ' .
179-
'or `Cake\Core\HttpApplicationInterface`, `stdClass` given.'
148+
'or `Authorization\AuthorizationServiceProviderInterface`, `stdClass` given.'
180149
);
181150

182151
$middleware = new AuthorizationMiddleware(new stdClass());

0 commit comments

Comments
 (0)