From bcce2625a8cb0b630d945c6849014049869e10ce Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 27 Nov 2018 12:01:36 +0100 Subject: Implemented AuthController for login * Moved /login functionality to AuthController * Refactored password handling logic to use the Authenticator --- src/Controllers/AuthController.php | 90 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 3 deletions(-) (limited to 'src/Controllers/AuthController.php') diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index cdaee167..e5fc40e3 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -2,8 +2,12 @@ namespace Engelsystem\Controllers; +use Carbon\Carbon; +use Engelsystem\Helpers\Authenticator; +use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGeneratorInterface; +use Engelsystem\Models\User\User; use Symfony\Component\HttpFoundation\Session\SessionInterface; class AuthController extends BaseController @@ -17,20 +21,100 @@ class AuthController extends BaseController /** @var UrlGeneratorInterface */ protected $url; - public function __construct(Response $response, SessionInterface $session, UrlGeneratorInterface $url) - { + /** @var Authenticator */ + protected $auth; + + /** @var array */ + protected $permissions = [ + 'login' => 'login', + 'postLogin' => 'login', + ]; + + /** + * @param Response $response + * @param SessionInterface $session + * @param UrlGeneratorInterface $url + * @param Authenticator $auth + */ + public function __construct( + Response $response, + SessionInterface $session, + UrlGeneratorInterface $url, + Authenticator $auth + ) { $this->response = $response; $this->session = $session; $this->url = $url; + $this->auth = $auth; + } + + /** + * @return Response + */ + public function login() + { + return $this->response->withView('pages/login'); + } + + /** + * Posted login form + * + * @param Request $request + * @return Response + */ + public function postLogin(Request $request): Response + { + $return = $this->authenticateUser($request->get('login', ''), $request->get('password', '')); + if (!$return instanceof User) { + return $this->response->withView( + 'pages/login', + ['errors' => [$return], 'show_password_recovery' => true] + ); + } + + $user = $return; + + $this->session->invalidate(); + $this->session->set('user_id', $user->id); + $this->session->set('locale', $user->settings->language); + + $user->last_login_at = new Carbon(); + $user->save(['touch' => false]); + + return $this->response->redirectTo('news'); } /** * @return Response */ - public function logout() + public function logout(): Response { $this->session->invalidate(); return $this->response->redirectTo($this->url->to('/')); } + + /** + * Verify the user and password + * + * @param $login + * @param $password + * @return User|string + */ + protected function authenticateUser(string $login, string $password) + { + if (!$login) { + return 'auth.no-nickname'; + } + + if (!$password) { + return 'auth.no-password'; + } + + if (!$user = $this->auth->authenticate($login, $password)) { + return 'auth.not-found'; + } + + return $user; + } } -- cgit v1.2.3-54-g00ecf From 6d5ada252202bfb29eba884cf9567e969d798607 Mon Sep 17 00:00:00 2001 From: Igor Scheller Date: Tue, 9 Jul 2019 22:02:07 +0200 Subject: Added validation to AuthController --- resources/lang/de_DE/default.mo | Bin 46271 -> 46206 bytes resources/lang/de_DE/default.po | 18 +++++--- resources/lang/en_US/default.mo | Bin 745 -> 770 bytes resources/lang/en_US/default.po | 16 ++++--- src/Controllers/AuthController.php | 62 ++++++++++++-------------- tests/Unit/Controllers/AuthControllerTest.php | 61 +++++++++++++++---------- 6 files changed, 88 insertions(+), 69 deletions(-) (limited to 'src/Controllers/AuthController.php') diff --git a/resources/lang/de_DE/default.mo b/resources/lang/de_DE/default.mo index 35ad80b7..fb93d590 100644 Binary files a/resources/lang/de_DE/default.mo and b/resources/lang/de_DE/default.mo differ diff --git a/resources/lang/de_DE/default.po b/resources/lang/de_DE/default.po index cd696610..1f0372af 100644 --- a/resources/lang/de_DE/default.po +++ b/resources/lang/de_DE/default.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Engelsystem\n" "POT-Creation-Date: 2019-04-28 15:23+0200\n" -"PO-Revision-Date: 2019-06-12 16:07+0200\n" +"PO-Revision-Date: 2019-06-13 11:54+0200\n" "Last-Translator: msquare \n" "Language-Team: \n" "Language: de_DE\n" @@ -1529,9 +1529,8 @@ msgstr "Nachname" msgid "Entry required!" msgstr "Pflichtfeld!" -#: includes/pages/guest_login.php:414 -msgid "auth.no-password" -msgstr "Gib bitte ein Passwort ein." +#~ msgid "auth.no-password" +#~ msgstr "Gib bitte ein Passwort ein." #: includes/pages/guest_login.php:418 msgid "auth.not-found" @@ -1539,9 +1538,8 @@ msgstr "" "Es wurde kein Engel gefunden. Probiere es bitte noch einmal. Wenn das Problem " "weiterhin besteht, melde dich im Himmel." -#: includes/pages/guest_login.php:451 includes/view/User_view.php:130 -msgid "auth.no-nickname" -msgstr "Gib bitte einen Nick an." +#~ msgid "auth.no-nickname" +#~ msgstr "Gib bitte einen Nick an." #: includes/pages/guest_login.php:481 #: includes/view/User_view.php:122 @@ -2765,3 +2763,9 @@ msgid "" msgstr "" "Diese Seite existiert nicht oder Du hast keinen Zugriff. Melde Dich an um " "Zugriff zu erhalten!" + +msgid "validation.password.required" +msgstr "Bitte gib ein Passwort an." + +msgid "validation.login.required" +msgstr "Bitte gib einen Loginnamen an." diff --git a/resources/lang/en_US/default.mo b/resources/lang/en_US/default.mo index e95ae703..7ef9c3b2 100644 Binary files a/resources/lang/en_US/default.mo and b/resources/lang/en_US/default.mo differ diff --git a/resources/lang/en_US/default.po b/resources/lang/en_US/default.po index 22566e52..54847e61 100644 --- a/resources/lang/en_US/default.po +++ b/resources/lang/en_US/default.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: Engelsystem 2.0\n" "POT-Creation-Date: 2017-12-29 19:01+0100\n" -"PO-Revision-Date: 2018-11-27 00:28+0100\n" +"PO-Revision-Date: 2019-06-04 23:41+0200\n" "Language-Team: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -16,11 +16,17 @@ msgstr "" "Language: en_US\n" "X-Poedit-SearchPath-0: .\n" -msgid "auth.no-nickname" -msgstr "Please enter a nickname." +#~ msgid "auth.no-nickname" +#~ msgstr "Please enter a nickname." -msgid "auth.no-password" -msgstr "Please enter a password." +#~ msgid "auth.no-password" +#~ msgstr "Please enter a password." msgid "auth.not-found" msgstr "No user was found. Please try again. If you are still having problems, ask Heaven." + +msgid "validation.password.required" +msgstr "The password is required." + +msgid "validation.login.required" +msgstr "The login name is required." diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index e5fc40e3..a8cc1ace 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -8,6 +8,8 @@ use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGeneratorInterface; use Engelsystem\Models\User\User; +use Illuminate\Support\Arr; +use Illuminate\Support\Collection; use Symfony\Component\HttpFoundation\Session\SessionInterface; class AuthController extends BaseController @@ -53,7 +55,22 @@ class AuthController extends BaseController */ public function login() { - return $this->response->withView('pages/login'); + return $this->showLogin(); + } + + /** + * @param bool $showRecovery + * @return Response + */ + protected function showLogin($showRecovery = false) + { + $errors = Collection::make(Arr::flatten($this->session->get('errors', []))); + $this->session->remove('errors'); + + return $this->response->withView( + 'pages/login', + ['errors' => $errors, 'show_password_recovery' => $showRecovery] + ); } /** @@ -64,15 +81,18 @@ class AuthController extends BaseController */ public function postLogin(Request $request): Response { - $return = $this->authenticateUser($request->get('login', ''), $request->get('password', '')); - if (!$return instanceof User) { - return $this->response->withView( - 'pages/login', - ['errors' => [$return], 'show_password_recovery' => true] - ); - } + $data = $this->validate($request, [ + 'login' => 'required', + 'password' => 'required', + ]); + + $user = $this->auth->authenticate($data['login'], $data['password']); - $user = $return; + if (!$user instanceof User) { + $this->session->set('errors', $this->session->get('errors', []) + ['auth.not-found']); + + return $this->showLogin(true); + } $this->session->invalidate(); $this->session->set('user_id', $user->id); @@ -93,28 +113,4 @@ class AuthController extends BaseController return $this->response->redirectTo($this->url->to('/')); } - - /** - * Verify the user and password - * - * @param $login - * @param $password - * @return User|string - */ - protected function authenticateUser(string $login, string $password) - { - if (!$login) { - return 'auth.no-nickname'; - } - - if (!$password) { - return 'auth.no-password'; - } - - if (!$user = $this->auth->authenticate($login, $password)) { - return 'auth.not-found'; - } - - return $user; - } } diff --git a/tests/Unit/Controllers/AuthControllerTest.php b/tests/Unit/Controllers/AuthControllerTest.php index 0fad3b6d..d3dbfa4b 100644 --- a/tests/Unit/Controllers/AuthControllerTest.php +++ b/tests/Unit/Controllers/AuthControllerTest.php @@ -4,15 +4,21 @@ namespace Engelsystem\Test\Unit\Controllers; use Engelsystem\Controllers\AuthController; use Engelsystem\Helpers\Authenticator; +use Engelsystem\Http\Exceptions\ValidationException; use Engelsystem\Http\Request; use Engelsystem\Http\Response; use Engelsystem\Http\UrlGeneratorInterface; +use Engelsystem\Http\Validation\Validates; +use Engelsystem\Http\Validation\Validator; use Engelsystem\Models\User\Settings; use Engelsystem\Models\User\User; use Engelsystem\Test\Unit\HasDatabase; +use Illuminate\Support\Collection; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Session\Session; use Symfony\Component\HttpFoundation\Session\SessionInterface; +use Symfony\Component\HttpFoundation\Session\Storage\MockArraySessionStorage; class AuthControllerTest extends TestCase { @@ -21,6 +27,7 @@ class AuthControllerTest extends TestCase /** * @covers \Engelsystem\Controllers\AuthController::__construct * @covers \Engelsystem\Controllers\AuthController::login + * @covers \Engelsystem\Controllers\AuthController::showLogin */ public function testLogin() { @@ -31,6 +38,10 @@ class AuthControllerTest extends TestCase /** @var Authenticator|MockObject $auth */ list(, $session, $url, $auth) = $this->getMocks(); + $session->expects($this->once()) + ->method('get') + ->with('errors', []) + ->willReturn(['foo' => 'bar']); $response->expects($this->once()) ->method('withView') ->with('pages/login') @@ -42,7 +53,6 @@ class AuthControllerTest extends TestCase /** * @covers \Engelsystem\Controllers\AuthController::postLogin - * @covers \Engelsystem\Controllers\AuthController::authenticateUser */ public function testPostLogin() { @@ -51,10 +61,12 @@ class AuthControllerTest extends TestCase $request = new Request(); /** @var Response|MockObject $response */ $response = $this->createMock(Response::class); - /** @var SessionInterface|MockObject $session */ /** @var UrlGeneratorInterface|MockObject $url */ /** @var Authenticator|MockObject $auth */ - list(, $session, $url, $auth) = $this->getMocks(); + list(, , $url, $auth) = $this->getMocks(); + $session = new Session(new MockArraySessionStorage()); + /** @var Validator|MockObject $validator */ + $validator = new Validator(new Validates()); $user = new User([ 'name' => 'foo', @@ -63,7 +75,7 @@ class AuthControllerTest extends TestCase 'api_key' => '', 'last_login_at' => null, ]); - $user->forceFill(['id' => 42,]); + $user->forceFill(['id' => 42]); $user->save(); $settings = new Settings(['language' => 'de_DE', 'theme' => '']); @@ -76,41 +88,42 @@ class AuthControllerTest extends TestCase ->with('foo', 'bar') ->willReturnOnConsecutiveCalls(null, $user); - $response->expects($this->exactly(3)) + $response->expects($this->once()) ->method('withView') - ->withConsecutive( - ['pages/login', ['errors' => ['auth.no-nickname'], 'show_password_recovery' => true]], - ['pages/login', ['errors' => ['auth.no-password'], 'show_password_recovery' => true]], - ['pages/login', ['errors' => ['auth.not-found'], 'show_password_recovery' => true]]) + ->with('pages/login', ['errors' => Collection::make(['auth.not-found']), 'show_password_recovery' => true]) ->willReturn($response); $response->expects($this->once()) ->method('redirectTo') ->with('news') ->willReturn($response); - $session->expects($this->once()) - ->method('invalidate'); - - $session->expects($this->exactly(2)) - ->method('set') - ->withConsecutive( - ['user_id', 42], - ['locale', 'de_DE'] - ); - + // No credentials $controller = new AuthController($response, $session, $url, $auth); - $controller->postLogin($request); + $controller->setValidator($validator); + try { + $controller->postLogin($request); + $this->fail('Login without credentials possible'); + } catch (ValidationException $e) { + } + + // Missing password + $request = new Request([], ['login' => 'foo']); + try { + $controller->postLogin($request); + $this->fail('Login without password possible'); + } catch (ValidationException $e) { + } - $request = new Request(['login' => 'foo']); - $controller->postLogin($request); - - $request = new Request(['login' => 'foo', 'password' => 'bar']); // No user found + $request = new Request([], ['login' => 'foo', 'password' => 'bar']); $controller->postLogin($request); + $this->assertEquals([], $session->all()); + // Authenticated user $controller->postLogin($request); $this->assertNotNull($user->last_login_at); + $this->assertEquals(['user_id' => 42, 'locale' => 'de_DE'], $session->all()); } /** -- cgit v1.2.3-54-g00ecf From b03102e3c613bd057f117a145d94aec4c977006c Mon Sep 17 00:00:00 2001 From: msquare Date: Sun, 21 Jul 2019 12:37:01 +0200 Subject: AuthController return types --- src/Controllers/AuthController.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/Controllers/AuthController.php') diff --git a/src/Controllers/AuthController.php b/src/Controllers/AuthController.php index a8cc1ace..55dd56b0 100644 --- a/src/Controllers/AuthController.php +++ b/src/Controllers/AuthController.php @@ -53,7 +53,7 @@ class AuthController extends BaseController /** * @return Response */ - public function login() + public function login(): Response { return $this->showLogin(); } @@ -62,7 +62,7 @@ class AuthController extends BaseController * @param bool $showRecovery * @return Response */ - protected function showLogin($showRecovery = false) + protected function showLogin($showRecovery = false): Response { $errors = Collection::make(Arr::flatten($this->session->get('errors', []))); $this->session->remove('errors'); -- cgit v1.2.3-54-g00ecf