Skip to content

Commit 746a234

Browse files
authored
Merge pull request #287 from cakephp/config-data
Move redirect configuration to the service
2 parents 72c26cf + 5fab345 commit 746a234

File tree

5 files changed

+373
-128
lines changed

5 files changed

+373
-128
lines changed

src/AuthenticationService.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,11 @@ class AuthenticationService implements AuthenticationServiceInterface
7979
* ]
8080
* ]);
8181
* ```
82+
* - `identityAttribute` - The request attribute to store the identity in.
83+
* - `unauthenticatedRedirect` - The URL to redirect unauthenticated errors to. See
84+
* AuthenticationComponent::allowUnauthenticated()
85+
* - `queryParam` - Set to a string to have unauthenticated redirects contain a `redirect` query string
86+
* parameter with the previously blocked URL.
8287
*
8388
* @var array
8489
*/
@@ -87,6 +92,8 @@ class AuthenticationService implements AuthenticationServiceInterface
8792
'identifiers' => [],
8893
'identityClass' => Identity::class,
8994
'identityAttribute' => 'identity',
95+
'queryParam' => null,
96+
'unauthorizedRedirect' => null,
9097
];
9198

9299
/**
@@ -291,6 +298,16 @@ public function getIdentity()
291298
return $identity;
292299
}
293300

301+
/**
302+
* Return the name of the identity attribute.
303+
*
304+
* @return string
305+
*/
306+
public function getIdentityAttribute()
307+
{
308+
return $this->getConfig('identityAttribute');
309+
}
310+
294311
/**
295312
* Builds the identity object
296313
*
@@ -317,4 +334,48 @@ public function buildIdentity($identityData)
317334

318335
return $identity;
319336
}
337+
338+
/**
339+
* Return the URL to redirect unauthenticated users to.
340+
*
341+
* If the `unauthenticaedRedirect` option is not set,
342+
* this method will return null.
343+
*
344+
* If the `queryParam` option is set a query parameter
345+
* will be appended with the denied URL path.
346+
*
347+
* @param \Psr\Http\Message\ServerRequestInterface $request The request
348+
* @return string|null
349+
*/
350+
public function getUnauthenticatedRedirectUrl(ServerRequestInterface $request)
351+
{
352+
$param = $this->getConfig('queryParam');
353+
$target = $this->getConfig('unauthenticatedRedirect');
354+
if ($target === null) {
355+
return null;
356+
}
357+
if ($param === null) {
358+
return $target;
359+
}
360+
361+
$uri = $request->getUri();
362+
if (property_exists($uri, 'base')) {
363+
$uri = $uri->withPath($uri->base . $uri->getPath());
364+
}
365+
$redirect = $uri->getPath();
366+
if ($uri->getQuery()) {
367+
$redirect .= '?' . $uri->getQuery();
368+
}
369+
$query = urlencode($param) . '=' . urlencode($redirect);
370+
371+
$url = parse_url($target);
372+
if (isset($url['query']) && strlen($url['query'])) {
373+
$url['query'] .= '&' . $query;
374+
} else {
375+
$url['query'] = $query;
376+
}
377+
$fragment = isset($url['fragment']) ? '#' . $url['fragment'] : '';
378+
379+
return $url['path'] . '?' . $url['query'] . $fragment;
380+
}
320381
}

src/AuthenticationServiceInterface.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,19 @@ public function getAuthenticationProvider();
6969
* @return \Authentication\Authenticator\ResultInterface|null Authentication result interface
7070
*/
7171
public function getResult();
72+
73+
/**
74+
* Return the name of the identity attribute.
75+
*
76+
* @return string
77+
*/
78+
public function getIdentityAttribute();
79+
80+
/**
81+
* Return the URL to redirect unauthenticated users to.
82+
*
83+
* @param \Psr\Http\Message\ServerRequestInterface $request The request
84+
* @return string|null
85+
*/
86+
public function getUnauthenticatedRedirectUrl(ServerRequestInterface $request);
7287
}

src/Middleware/AuthenticationMiddleware.php

Lines changed: 26 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
namespace Authentication\Middleware;
1616

17+
use Authentication\AuthenticationService;
1718
use Authentication\AuthenticationServiceInterface;
1819
use Authentication\AuthenticationServiceProviderInterface;
1920
use Authentication\Authenticator\UnauthenticatedException;
@@ -35,18 +36,18 @@ class AuthenticationMiddleware
3536
/**
3637
* Configuration options
3738
*
38-
* - `identityAttribute` - The request attribute to store the identity in.
3939
* - `name` the application hook method to call. Will be prefixed with `authentication`
40+
*
41+
* The following keys are deprecated and should instead be set on the AuthenticationService
42+
*
43+
* - `identityAttribute` - The request attribute to store the identity in.
4044
* - `unauthenticatedRedirect` - The URL to redirect unauthenticated errors to. See
4145
* AuthenticationComponent::allowUnauthenticated()
4246
* - `queryParam` - Set to true to have unauthenticated redirects contain a `redirect` query string
4347
* parameter with the previously blocked URL.
4448
*/
4549
protected $_defaultConfig = [
46-
'identityAttribute' => 'identity',
4750
'name' => null,
48-
'unauthenticatedRedirect' => null,
49-
'queryParam' => null,
5051
];
5152

5253
/**
@@ -111,7 +112,7 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
111112
}
112113

113114
$request = $result['request'];
114-
$request = $request->withAttribute($this->getConfig('identityAttribute'), $service->getIdentity());
115+
$request = $request->withAttribute($service->getIdentityAttribute(), $service->getIdentity());
115116
$request = $request->withAttribute('authentication', $service);
116117
$request = $request->withAttribute('authenticationResult', $result['result']);
117118

@@ -120,10 +121,8 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
120121
try {
121122
return $next($request, $response);
122123
} catch (UnauthenticatedException $e) {
123-
$target = $this->getConfig('unauthenticatedRedirect');
124-
if ($target) {
125-
$url = $this->getRedirectUrl($target, $request);
126-
124+
$url = $service->getUnauthenticatedRedirectUrl($request);
125+
if ($url) {
127126
return $response
128127
->withStatus(302)
129128
->withHeader('Location', $url);
@@ -132,41 +131,6 @@ public function __invoke(ServerRequestInterface $request, ResponseInterface $res
132131
}
133132
}
134133

135-
/**
136-
* Returns redirect URL.
137-
*
138-
* @param string $target Redirect target.
139-
* @param \Psr\Http\Message\ServerRequestInterface $request Request instance.
140-
* @return string
141-
*/
142-
protected function getRedirectUrl($target, ServerRequestInterface $request)
143-
{
144-
$param = $this->getConfig('queryParam');
145-
if ($param === null) {
146-
return $target;
147-
}
148-
149-
$uri = $request->getUri();
150-
if (property_exists($uri, 'base')) {
151-
$uri = $uri->withPath($uri->base . $uri->getPath());
152-
}
153-
$redirect = $uri->getPath();
154-
if ($uri->getQuery()) {
155-
$redirect .= '?' . $uri->getQuery();
156-
}
157-
$query = urlencode($param) . '=' . urlencode($redirect);
158-
159-
$url = parse_url($target);
160-
if (isset($url['query']) && strlen($url['query'])) {
161-
$url['query'] .= '&' . $query;
162-
} else {
163-
$url['query'] = $query;
164-
}
165-
$fragment = isset($url['fragment']) ? '#' . $url['fragment'] : '';
166-
167-
return $url['path'] . '?' . $url['query'] . $fragment;
168-
}
169-
170134
/**
171135
* Returns AuthenticationServiceInterface instance.
172136
*
@@ -189,6 +153,24 @@ protected function getAuthenticationService($request, $response)
189153

190154
throw new RuntimeException($message);
191155
}
156+
$forwardKeys = ['identityAttribute', 'unauthenticatedRedirect', 'queryParam'];
157+
foreach ($forwardKeys as $key) {
158+
$value = $this->getConfig($key);
159+
if ($value) {
160+
deprecationWarning(
161+
"The `{$key}` configuration key on AuthenticationMiddleware is deprecated. " .
162+
"Instead set the `{$key}` on your AuthenticationService instance."
163+
);
164+
if ($subject instanceof AuthenticationService) {
165+
$subject->setConfig($key, $value);
166+
} else {
167+
throw new RuntimeException(
168+
'Could not forward configuration to authentication service as ' .
169+
'it does not implement `getConfig()`'
170+
);
171+
}
172+
}
173+
}
192174

193175
return $subject;
194176
}

tests/TestCase/AuthenticationServiceTest.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,4 +627,65 @@ public function testGetIdentityInterface()
627627

628628
$this->assertSame($identity, $service->getIdentity());
629629
}
630+
631+
public function testGetIdentityAttribute()
632+
{
633+
$service = new AuthenticationService(['identityAttribute' => 'user']);
634+
$this->assertSame('user', $service->getIdentityAttribute());
635+
}
636+
637+
public function testGetUnauthenticatedRedirectUrlNoValues()
638+
{
639+
$service = new AuthenticationService();
640+
$request = new ServerRequest();
641+
642+
$this->assertNull($service->getUnauthenticatedRedirectUrl($request));
643+
}
644+
645+
public function testGetUnauthenticatedRedirectUrl()
646+
{
647+
$service = new AuthenticationService();
648+
$request = ServerRequestFactory::fromGlobals(
649+
['REQUEST_URI' => '/secrets']
650+
);
651+
$service->setConfig('unauthenticatedRedirect', '/users/login');
652+
$this->assertSame('/users/login', $service->getUnauthenticatedRedirectUrl($request));
653+
654+
$service->setConfig('queryParam', 'redirect');
655+
$this->assertSame(
656+
'/users/login?redirect=%2Fsecrets',
657+
$service->getUnauthenticatedRedirectUrl($request)
658+
);
659+
660+
$service->setConfig('unauthenticatedRedirect', '/users/login?foo=bar');
661+
$this->assertSame(
662+
'/users/login?foo=bar&redirect=%2Fsecrets',
663+
$service->getUnauthenticatedRedirectUrl($request)
664+
);
665+
666+
$service->setConfig('unauthenticatedRedirect', '/users/login?foo=bar#fragment');
667+
$this->assertSame(
668+
'/users/login?foo=bar&redirect=%2Fsecrets#fragment',
669+
$service->getUnauthenticatedRedirectUrl($request)
670+
);
671+
}
672+
673+
public function testGetUnauthenticatedRedirectUrlWithBasePath()
674+
{
675+
$request = ServerRequestFactory::fromGlobals(
676+
['REQUEST_URI' => '/secrets']
677+
);
678+
$uri = $request->getUri();
679+
$uri->base = '/base';
680+
$request = $request->withUri($uri);
681+
682+
$service = new AuthenticationService([
683+
'unauthenticatedRedirect' => '/users/login',
684+
'queryParam' => 'redirect',
685+
]);
686+
$this->assertSame(
687+
'/users/login?redirect=%2Fbase%2Fsecrets',
688+
$service->getUnauthenticatedRedirectUrl($request)
689+
);
690+
}
630691
}

0 commit comments

Comments
 (0)