Skip to content

Commit

Permalink
#9566 Laravel auth system integration (#9596)
Browse files Browse the repository at this point in the history
* WIP replace sessions with Laravel

* #9566 Laravel auth system integration

* #9566 fixing session disable const checking and initialization

* #9566 laravel session WIP

* #9566 session regenration and old session manager clean up

* #9566 added remember me functionality

* #9566 fixed logout with auth key details persistence

* #9566 fixed device force logout redirect issue

* #9566 fixed login issue after migration from older session implementation

* #9566 completed sign in/out as and updated session data update in PKPRequest::__destruct

* #9566 updates based on PR review

* #9566 added check to make sure seesion table exists before saving session

* #9566 moved session storage update within register_shutdown_function

* #9566 removed unused function param

* #9566 added upgrade migration

* #9566 fixed issue and doc blocks based on PR review

* #9566 removed older implementation cookie issue override method as fixed by setting domain

* #9566 removed previously added application upgrade settings from migration tool

* #9566 trying to fix mysql build issue

* #9566 added db service provider re-registration at install time

* #9566 added cookie encryption ability

* #9566 session disable check moved to PKPSessionGuard with session user_id key update

* #9566 fixed typo

* #9566 command line session issue

* #9566 clean up of old session manager and dao related implementations

* #9566 session default base path update

* #9566 session default base path revert back

* #9566 fixed cookie path issue

* #9566 removed AUTH_KEY_* const usage and related code

---------

Co-authored-by: Alec Smecher <alec@smecher.bc.ca>
  • Loading branch information
touhidurabir and asmecher authored Apr 16, 2024
1 parent 6b52af7 commit 5b34729
Show file tree
Hide file tree
Showing 60 changed files with 1,404 additions and 1,181 deletions.
5 changes: 3 additions & 2 deletions classes/cliTool/CommandLineTool.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
use APP\core\PageRouter;
use APP\facades\Repo;
use PKP\config\Config;
use PKP\core\PKPSessionGuard;
use PKP\core\Registry;
use PKP\plugins\PluginRegistry;
use PKP\session\SessionManager;
use PKP\user\User;

/** Initialization code */
Expand All @@ -39,8 +39,9 @@
if (!defined('STDIN')) {
define('STDIN', fopen('php://stdin', 'r'));
}

require_once './lib/pkp/includes/bootstrap.php';
SessionManager::disable();
PKPSessionGuard::disableSession();

class CommandLineTool
{
Expand Down
2 changes: 1 addition & 1 deletion classes/controllers/grid/feature/OrderItemsFeature.php
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ public function setOptions($request, $grid)
$router = $request->getRouter();
$this->addOptions([
'saveItemsSequenceUrl' => $router->url($request, null, null, 'saveSequence', null, $grid->getRequestArgs()),
'csrfToken' => $request->getSession()->getCsrfToken(),
'csrfToken' => $request->getSession()->token(),
]);
}

Expand Down
6 changes: 0 additions & 6 deletions classes/core/APIRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use APP\core\Application;
use Exception;
use Illuminate\Http\Response;
use PKP\session\SessionManager;

class APIRouter extends PKPRouter
{
Expand Down Expand Up @@ -95,11 +94,6 @@ public function route($request)
exit;
}

if (!SessionManager::isDisabled()) {
// Initialize session
SessionManager::getManager();
}

$handler = require('./' . $sourceFile);
$this->setHandler($handler);
}
Expand Down
46 changes: 45 additions & 1 deletion classes/core/Dispatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
namespace PKP\core;

use APP\core\Services;
use PKP\core\PKPSessionGuard;
use PKP\config\Config;
use PKP\plugins\Hook;
use PKP\plugins\PluginRegistry;
Expand Down Expand Up @@ -122,7 +123,10 @@ public function dispatch($request)
// Inject router and dispatcher into request
$request->setRouter($routerCandidate);
$request->setDispatcher($this);


$this->setUserResolver();
$this->initSession();

// We've found our router and can go on
// to handle the request.
$router = & $routerCandidate;
Expand Down Expand Up @@ -167,6 +171,46 @@ public function dispatch($request)
$router->route($request);
}

/**
* Init the session by running through session related middleware
*/
public function initSession(): void
{
if (PKPSessionGuard::isSessionDisable()) {
return;
}

$illuminateRequest = app(\Illuminate\Http\Request::class); /** @var \Illuminate\Http\Request $illuminateRequest */

(new \Illuminate\Pipeline\Pipeline(PKPContainer::getInstance()))
->send($illuminateRequest)
->through(
app()->has('encrypter')
? [
\PKP\middleware\PKPEncryptCookies::class,
\Illuminate\Session\Middleware\StartSession::class,
\PKP\middleware\PKPAuthenticateSession::class,
] : [
\Illuminate\Session\Middleware\StartSession::class,
\PKP\middleware\PKPAuthenticateSession::class,
]
)
->via('handle')
->then(function (\Illuminate\Http\Request $request) {
return app()->get(\Illuminate\Http\Response::class);
});
}

/**
* Set the user resolving logic for laravel inner use purpose
*/
public function setUserResolver(): void
{
$illuminateRequest = app()->get(\Illuminate\Http\Request::class); /** @var \Illuminate\Http\Request $illuminateRequest */

$illuminateRequest->setUserResolver(fn () => \APP\core\Application::get()->getRequest()->getUser());
}

/**
* Build a handler request URL into PKPApplication.
*
Expand Down
8 changes: 4 additions & 4 deletions classes/core/PKPApplication.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
use Illuminate\Database\Events\QueryExecuted;
use Illuminate\Database\MySqlConnection;
use Illuminate\Support\Facades\DB;
use PKP\core\PKPSessionGuard;
use PKP\config\Config;
use PKP\db\DAORegistry;
use PKP\facades\Locale;
use PKP\security\Role;
use PKP\session\SessionManager;
use PKP\site\VersionDAO;
use PKP\submission\RepresentationDAOInterface;

Expand Down Expand Up @@ -188,8 +188,9 @@ class_alias('\PKP\core\PKPApplication', '\PKPApplication');
}

ini_set('display_errors', Config::getVar('debug', 'display_errors', ini_get('display_errors')));
if (!static::isInstalled()) {
SessionManager::disable();

if (!static::isInstalled() && !PKPSessionGuard::isSessionDisable()) {
PKPSessionGuard::disableSession();
}

Registry::set('application', $this);
Expand Down Expand Up @@ -497,7 +498,6 @@ public function getDAOMap()
'ReviewRoundDAO' => 'PKP\submission\reviewRound\ReviewRoundDAO',
'RoleDAO' => 'PKP\security\RoleDAO',
'ScheduledTaskDAO' => 'PKP\scheduledTask\ScheduledTaskDAO',
'SessionDAO' => 'PKP\session\SessionDAO',
'SiteDAO' => 'PKP\site\SiteDAO',
'StageAssignmentDAO' => 'PKP\stageAssignment\StageAssignmentDAO',
'SubEditorsDAO' => 'PKP\context\SubEditorsDAO',
Expand Down
118 changes: 118 additions & 0 deletions classes/core/PKPAuthManager.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php

/**
* @file classes/core/PKPAuthManager.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPAuthManager
*
* @brief Register session guard and appropriate user provider to handle authentication
*/

namespace PKP\core;

use APP\facades\Repo;
use APP\core\Application;
use InvalidArgumentException;
use PKP\core\PKPSessionGuard;
use PKP\core\PKPUserProvider;

class PKPAuthManager extends \Illuminate\Auth\AuthManager
{
/**
* @copydoc \Illuminate\Auth\AuthManager::$app
*
* @var \Illuminate\Contracts\Foundation\Application|\PKP\core\PKPContainer
*/
protected $app;

/**
* @copydoc \Illuminate\Auth\AuthManager::__construct($app)
*/
public function __construct($app)
{
$this->app = $app;

$this->userResolver = function ($guard = null) {

if ($userId = Application::get()->getRequest()->getSessionGuard()->getUserId()) {
return Repo::user()->get($userId);
}

return null;
};
}

/**
* @copydoc \Illuminate\Auth\AuthManager::createUserProvider($provider = null)
*/
public function createUserProvider($provider = null)
{
if (is_null($config = $this->getProviderConfiguration($provider))) {
return;
}

if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
return call_user_func(
$this->customProviderCreators[$driver], $this->app, $config
);
}

return match ($driver) {
'database' => $this->createDatabaseProvider($config),
'eloquent' => $this->createEloquentProvider($config),
PKPUserProvider::AUTH_PROVIDER => $this->createPKPUserProvider($config),
default => throw new InvalidArgumentException(
"Authentication user provider [{$driver}] is not defined."
),
};
}

/**
* Create an instance of the PKPUserProvider.
*/
public function createPKPUserProvider(array $config = []): PKPUserProvider
{
return app()->get(PKPUserProvider::class);
}

/**
* @copydoc \Illuminate\Auth\AuthManager::createSessionDriver($name, $config)
*
* @return \PKP\core\PKPSessionGuard
*/
public function createSessionDriver($name, $config)
{
$provider = $this->createUserProvider($config['provider'] ?? null);

$guard = new PKPSessionGuard(
$name,
$provider,
$this->app['session.store'],
);

// When using the remember me functionality of the authentication services
// we will need to set the encryption instance of the guard, which allows
// secure, encrypted cookie values to get generated for those cookies.
if (method_exists($guard, 'setCookieJar')) {
$guard->setCookieJar($this->app['cookie']);
}

if (method_exists($guard, 'setDispatcher')) {
$guard->setDispatcher($this->app['events']);
}

if (method_exists($guard, 'setRequest')) {
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
}

if (isset($config['remember'])) {
$guard->setRememberDuration($config['remember']);
}

return $guard;
}
}
72 changes: 72 additions & 0 deletions classes/core/PKPAuthServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

/**
* @file classes/core/PKPAuthServiceProvider.php
*
* Copyright (c) 2024 Simon Fraser University
* Copyright (c) 2024 John Willinsky
* Distributed under the GNU GPL v3. For full terms see the file docs/COPYING.
*
* @class PKPAuthServiceProvider
*
* @brief Register auth driver, manager and related services
*/

namespace PKP\core;

use PKP\core\PKPAuthManager;
use PKP\core\PKPUserProvider;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Database\ConnectionInterface;
use Illuminate\Contracts\Auth\Factory as AuthFactory;

class PKPAuthServiceProvider extends \Illuminate\Auth\AuthServiceProvider
{
/**
* Bootstrap any application services.
*/
public function boot()
{
Auth::provider(
PKPUserProvider::AUTH_PROVIDER,
fn ($app, array $config) => $app->get(PKPUserProvider::class)
);
}

/**
* @copydoc \Illuminate\Auth\AuthServiceProvider::register()
*/
public function register()
{
parent::register();

$this->app->singleton(AuthFactory::class, fn($app) => $app->get('auth'));

$this->app->singleton(
PKPUserProvider::class,
fn ($app) => new PKPUserProvider(
$app->get(ConnectionInterface::class),
new \Illuminate\Hashing\BcryptHasher(),
'users'
)
);

$this->app->singleton(Guard::class, fn ($app) => $app->get('auth.driver'));

$this->app->bind(
\Illuminate\Contracts\Cookie\QueueingFactory::class,
fn ($app) => $app->get('cookie')
);
}

/**
* @copydoc \Illuminate\Auth\AuthServiceProvider::registerAuthenticator()
*/
protected function registerAuthenticator()
{
$this->app->singleton('auth', fn ($app) => new PKPAuthManager($app));

$this->app->singleton('auth.driver', fn ($app) => $app['auth']->guard());
}
}
4 changes: 2 additions & 2 deletions classes/core/PKPBaseController.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Routing\Route;
use PKP\core\PKPSessionGuard;
use PKP\security\authorization\AllowedHostsPolicy;
use PKP\security\authorization\AuthorizationDecisionManager;
use PKP\security\authorization\AuthorizationPolicy;
use PKP\security\authorization\HttpsPolicy;
use PKP\security\authorization\PolicySet;
use PKP\security\authorization\RestrictedSiteAccessPolicy;
use PKP\security\authorization\UserRolesRequiredPolicy;
use PKP\session\SessionManager;
use PKP\statistics\PKPStatisticsHelper;
use PKP\validation\ValidatorFactory;
use ReflectionFunction;
Expand Down Expand Up @@ -332,7 +332,7 @@ public function authorize(PKPRequest $request, array &$args, array $roleAssignme

// Ensure the allowed hosts setting, when provided, is respected.
$this->addPolicy(new AllowedHostsPolicy($request), true);
if (!SessionManager::isDisabled()) {
if (!PKPSessionGuard::isSessionDisable()) {
// Add user roles in authorized context.
$user = $request->getUser();
if ($user instanceof \PKP\user\User) {
Expand Down
Loading

0 comments on commit 5b34729

Please sign in to comment.