summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnold Daniels <arnold@jasny.net>2016-12-28 23:21:09 +0100
committerArnold Daniels <arnold@jasny.net>2016-12-28 23:21:09 +0100
commit233a9aeb56144244092ac8270ede99342d9be616 (patch)
tree567fac369ca18a3c3347b7817a87493502215852
parent0d68005825997c8a5152fb67afc7814b2b064bc7 (diff)
downloadauth-233a9aeb56144244092ac8270ede99342d9be616.zip
auth-233a9aeb56144244092ac8270ede99342d9be616.tar.gz
auth-233a9aeb56144244092ac8270ede99342d9be616.tar.bz2
Added `Auth::asMiddleware()`
Middleware now works with Auth and Authz is optional If getRequiredRole returns a boolean, just check if a user is logged in
-rw-r--r--composer.json3
-rw-r--r--src/Auth.php14
-rw-r--r--src/Auth/Middleware.php24
-rw-r--r--tests/Auth/MiddlewareTest.php77
-rw-r--r--tests/AuthTest.php14
-rw-r--r--tests/support/TestAuth.php10
6 files changed, 119 insertions, 23 deletions
diff --git a/composer.json b/composer.json
index 2b2bd81..74737c5 100644
--- a/composer.json
+++ b/composer.json
@@ -24,6 +24,9 @@
"Jasny\\": "src/"
}
},
+ "autoload-dev": {
+ "classmap": ["tests/support"]
+ },
"require-dev": {
"jasny/php-code-quality": "^2.1.2",
"hashids/hashids": "~2.0.0"
diff --git a/src/Auth.php b/src/Auth.php
index 3f70fbf..25ea33f 100644
--- a/src/Auth.php
+++ b/src/Auth.php
@@ -3,6 +3,7 @@
namespace Jasny;
use Jasny\Auth\User;
+use Jasny\Auth\Middleware;
/**
* Authentication and access control
@@ -165,4 +166,17 @@ abstract class Auth
$this->user = false;
$this->persistCurrentUser();
}
+
+
+ /**
+ * Create auth middleware interface for access control.
+ *
+ * @param Authz $auth
+ * @param callable $getRequiredRole
+ * @return Middleware
+ */
+ public function asMiddleware($getRequiredRole)
+ {
+ return new Middleware($this, $getRequiredRole);
+ }
}
diff --git a/src/Auth/Middleware.php b/src/Auth/Middleware.php
index 1700125..248feac 100644
--- a/src/Auth/Middleware.php
+++ b/src/Auth/Middleware.php
@@ -26,10 +26,10 @@ class Middleware
/**
* Class constructor
*
- * @param Authz $auth
+ * @param Auth $auth
* @param callable $getRequiredRole
*/
- public function __construct(Authz $auth, $getRequiredRole)
+ public function __construct(Auth $auth, $getRequiredRole)
{
$this->auth = $auth;
@@ -43,15 +43,23 @@ class Middleware
/**
* Check if the current user has one of the roles
*
- * @param array $roles
+ * @param array|string|boolean $roles
* @return
*/
- protected function hasRole(array $roles)
+ protected function hasRole($requiredRole)
{
+ if (is_bool($requiredRole)) {
+ return $this->auth->user() !== null;
+ }
+
$ret = false;
- foreach ($roles as $role) {
- $ret = $ret || $this->auth->is($role);
+ if ($this->auth instanceof Authz) {
+ $roles = (array)$requiredRole;
+
+ foreach ($roles as $role) {
+ $ret = $ret || $this->auth->is($role);
+ }
}
return $ret;
@@ -66,7 +74,7 @@ class Middleware
*/
protected function forbidden(ServerRequestInterface $request, ResponseInterface $response)
{
- $unauthorized = $this->auth instanceof Auth && $this->auth->user() === null;
+ $unauthorized = $this->auth->user() === null;
$forbiddenResponse = $response->withStatus($unauthorized ? 401 : 403);
$forbiddenResponse->getBody()->write('Access denied');
@@ -90,7 +98,7 @@ class Middleware
$requiredRole = call_user_func($this->getRequiredRole, $request);
- if (!empty($requiredRole) && !$this->hasRole((array)$requiredRole)) {
+ if (!empty($requiredRole) && !$this->hasRole($requiredRole)) {
return $this->forbidden($request, $response);
}
diff --git a/tests/Auth/MiddlewareTest.php b/tests/Auth/MiddlewareTest.php
index a07486f..bba5357 100644
--- a/tests/Auth/MiddlewareTest.php
+++ b/tests/Auth/MiddlewareTest.php
@@ -4,6 +4,7 @@ namespace Jasny\Auth;
use Jasny\Auth;
use Jasny\Authz;
+use Jasny\AuthAuthz;
use Jasny\Auth\Middleware;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\ResponseInterface;
@@ -32,7 +33,8 @@ class MiddlewareTest extends TestCase
public function setUp()
{
- $this->auth = $this->createMock(Authz::class);
+ $this->auth = $this->createMock(AuthAuthz::class);
+
$this->middleware = new Middleware($this->auth, function(ServerRequestInterface $request) {
return $request->getAttribute('auth');
});
@@ -45,11 +47,34 @@ class MiddlewareTest extends TestCase
{
new Middleware($this->auth, 'foo bar zoo');
}
+
- public function testInvokeWithoutRequiredRole()
+ public function testInvokeWithoutRequiredUser()
{
- $this->auth->expects($this->never())->method('is');
+ $this->auth->expects($this->never())->method('user');
+
+ $request = $this->createMock(ServerRequestInterface::class);
+ $request->expects($this->once())->method('getAttribute')->with('auth')->willReturn(false);
+
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ $response = $this->createMock(ResponseInterface::class);
+ $response->expects($this->never())->method('withStatus');
+
+ $next = $this->createCallbackMock(
+ $this->once(),
+ function(InvocationMocker $invoke) use ($request, $response, $finalResponse) {
+ $invoke->with($this->identicalTo($request), $this->identicalTo($response))->willReturn($finalResponse);
+ }
+ );
+
+ $result = call_user_func($this->middleware, $request, $response, $next);
+ $this->assertSame($finalResponse, $result);
+ }
+
+ public function testInvokeWithoutRequiredRole()
+ {
$request = $this->createMock(ServerRequestInterface::class);
$request->expects($this->once())->method('getAttribute')->with('auth')->willReturn(null);
@@ -70,6 +95,31 @@ class MiddlewareTest extends TestCase
$this->assertSame($finalResponse, $result);
}
+ public function testInvokeWithRequiredUser()
+ {
+ $user = $this->createMock(Authz\User::class);
+ $this->auth->expects($this->once())->method('user')->willReturn($user);
+
+ $request = $this->createMock(ServerRequestInterface::class);
+ $request->expects($this->once())->method('getAttribute')->with('auth')->willReturn(true);
+
+ $finalResponse = $this->createMock(ResponseInterface::class);
+
+ $response = $this->createMock(ResponseInterface::class);
+ $response->expects($this->never())->method('withStatus');
+
+ $next = $this->createCallbackMock(
+ $this->once(),
+ function(InvocationMocker $invoke) use ($request, $response, $finalResponse) {
+ $invoke->with($this->identicalTo($request), $this->identicalTo($response))->willReturn($finalResponse);
+ }
+ );
+
+ $result = call_user_func($this->middleware, $request, $response, $next);
+
+ $this->assertSame($finalResponse, $result);
+ }
+
public function testInvokeWithRequiredRole()
{
$this->auth->expects($this->once())->method('is')->with('user')->willReturn(true);
@@ -94,10 +144,13 @@ class MiddlewareTest extends TestCase
$this->assertSame($finalResponse, $result);
}
- public function testInvokeForbidden()
+ public function testInvokeUnauthorized()
{
+ $this->auth->expects($this->once())->method('user')->willReturn(null);
$this->auth->expects($this->once())->method('is')->with('user')->willReturn(false);
+ $this->setPrivateProperty($this->middleware, 'auth', $this->auth);
+
$request = $this->createMock(ServerRequestInterface::class);
$request->expects($this->once())->method('getAttribute')->with('auth')->willReturn('user');
@@ -108,7 +161,7 @@ class MiddlewareTest extends TestCase
$forbiddenResponse->expects($this->once())->method('getBody')->willReturn($stream);
$response = $this->createMock(ResponseInterface::class);
- $response->expects($this->once())->method('withStatus')->with(403)->willReturn($forbiddenResponse);
+ $response->expects($this->once())->method('withStatus')->with(401)->willReturn($forbiddenResponse);
$next = $this->createCallbackMock($this->never());
@@ -117,19 +170,13 @@ class MiddlewareTest extends TestCase
$this->assertSame($forbiddenResponse, $result);
}
- public function testInvokeUnauthorized()
+ public function testInvokeForbidden()
{
- $this->auth = $this->getMockBuilder(Auth::class)
- ->disableProxyingToOriginalMethods()
- ->setMethods(['user', 'is', 'persistCurrentUser', 'getCurrentUserId', 'fetchUserById',
- 'fetchUserByUsername'])
- ->getMock();
+ $user = $this->createMock(Authz\User::class);
- $this->auth->expects($this->once())->method('user')->willReturn(null);
+ $this->auth->expects($this->once())->method('user')->willReturn($user);
$this->auth->expects($this->once())->method('is')->with('user')->willReturn(false);
- $this->setPrivateProperty($this->middleware, 'auth', $this->auth);
-
$request = $this->createMock(ServerRequestInterface::class);
$request->expects($this->once())->method('getAttribute')->with('auth')->willReturn('user');
@@ -140,7 +187,7 @@ class MiddlewareTest extends TestCase
$forbiddenResponse->expects($this->once())->method('getBody')->willReturn($stream);
$response = $this->createMock(ResponseInterface::class);
- $response->expects($this->once())->method('withStatus')->with(401)->willReturn($forbiddenResponse);
+ $response->expects($this->once())->method('withStatus')->with(403)->willReturn($forbiddenResponse);
$next = $this->createCallbackMock($this->never());
diff --git a/tests/AuthTest.php b/tests/AuthTest.php
index 40177bd..be3f837 100644
--- a/tests/AuthTest.php
+++ b/tests/AuthTest.php
@@ -5,12 +5,15 @@ namespace Jasny;
use Jasny\Auth;
use PHPUnit_Framework_TestCase as TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Jasny\TestHelper;
/**
* @covers Jasny\Auth
*/
class AuthTest extends TestCase
{
+ use TestHelper;
+
/**
* @var Auth|MockObject
*/
@@ -177,4 +180,15 @@ class AuthTest extends TestCase
// Logout again shouldn't really do anything
$this->auth->logout();
}
+
+
+ public function testAsMiddleware()
+ {
+ $callback = $this->createCallbackMock($this->never());
+ $middleware = $this->auth->asMiddleware($callback);
+
+ $this->assertInstanceOf(Auth\Middleware::class, $middleware);
+ $this->assertAttributeEquals($this->auth, 'auth', $middleware);
+ $this->assertAttributeEquals($callback, 'getRequiredRole', $middleware);
+ }
}
diff --git a/tests/support/TestAuth.php b/tests/support/TestAuth.php
new file mode 100644
index 0000000..eadfacc
--- /dev/null
+++ b/tests/support/TestAuth.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Jasny;
+
+/**
+ * Auth class that implements Authz
+ */
+abstract class AuthAuthz extends Auth implements Authz
+{
+} \ No newline at end of file