Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion htdocs/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,14 @@ function array_find(array $array, callable $callback)
// Middleware that happens on every request. This doesn't include
// any authentication middleware, because that's done dynamically
// based on the module router, depending on if the module is public.
$middlewarechain = (new \LORIS\Middleware\Language())
$middlewarechain = (new \LORIS\Middleware\RequestAttributeBuilder())
->withMiddleware(new \LORIS\Middleware\Language())
->withMiddleware(new \LORIS\Middleware\ContentLength())
->withMiddleware(new \LORIS\Middleware\LorisMenu())
->withMiddleware(new \LORIS\Middleware\ContentLength())
->withMiddleware(new \LORIS\Middleware\AWS())
->withMiddleware(new \LORIS\Middleware\ContentSecurityPolicy())
->withMiddleware(new \LORIS\Middleware\RedirectControl())
->withMiddleware(new \LORIS\Middleware\MFA())
->withMiddleware(new \LORIS\Middleware\ResponseGenerator());

Expand Down
64 changes: 64 additions & 0 deletions src/Middleware/RedirectControl.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php declare(strict_types=1);

namespace LORIS\Middleware;

use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\MiddlewareInterface;
use \Psr\Http\Server\RequestHandlerInterface;

/**
* A Redirect middleware is a chainable type of PSR15-based middleware
* which checks the "redirect" query param element.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
class RedirectControl implements MiddlewareInterface, MiddlewareChainer
{
use MiddlewareChainerMixin;

/**
* {@inheritDoc}
*
* @param ServerRequestInterface $request The incoming PSR7 request.
* @param RequestHandlerInterface $handler The PSR15 handler to delegate
* content generation to.
*
* @return ResponseInterface the PSR15 response
*/
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
) : ResponseInterface {
// no redirect, skip to/follow normal process
$queryString = $request->getServerParams()['QUERY_STRING'] ?? null;
if ($queryString === null || !str_contains($queryString, "redirect")) {
return $this->next->process($request, $handler);
}

// if redirect in query string, check if a query parameter has a
// redirection set for a third-party
$query = $request->getQueryParams();
if (array_key_exists("redirect", $query)) {
// redirect uri
$redirect = rtrim($query["redirect"], "/");

// if the redirection does not starts with current host, it is
// trying to redirect outside, then force redirect to main/login page.
$uri = $request->getUri();
$baseURL = $request->getAttribute("baseurl");
if (!str_starts_with($redirect, $baseURL)) {
error_log("[error][redirect] Tentative of redirection outside of LORIS: {$redirect}");

// nullify uri query parameters
$uri = $uri->withQuery("");

// force reload the current host without redirect query param
return new \LORIS\Http\Response\JSON\SeeOther($uri);
}
}

//
return $this->next->process($request, $handler);
}
}
62 changes: 62 additions & 0 deletions src/Middleware/RequestAttributeBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php declare(strict_types=1);

namespace LORIS\Middleware;

use \Psr\Http\Message\ServerRequestInterface;
use \Psr\Http\Message\ResponseInterface;
use \Psr\Http\Server\MiddlewareInterface;
use \Psr\Http\Server\RequestHandlerInterface;

/**
* A RequestAttributeMBuilder middleware is a chainable type of PSR15-based
* middleware which add/modify the requests attributes.
*
* @license http://www.gnu.org/licenses/gpl-3.0.txt GPLv3
*/
class RequestAttributeBuilder implements MiddlewareInterface, MiddlewareChainer
{
use MiddlewareChainerMixin;

/**
* {@inheritDoc}
*
* @param ServerRequestInterface $request The incoming PSR7 request.
* @param RequestHandlerInterface $handler The PSR15 handler to delegate
* content generation to.
*
* @return ResponseInterface the PSR15 response
*/
public function process(
ServerRequestInterface $request,
RequestHandlerInterface $handler
) : ResponseInterface {
// use it once at the top of the middleware call
$factory = \NDB_Factory::singleton();

// add user to request attributes
$user = $factory->user();
$request = $request->withAttribute("user", $user);

// add loris instance to request attributes
$lorisInstance = new \LORIS\LorisInstance(
$factory->database(),
$factory->config(),
[
__DIR__ . "/../../project/modules",
__DIR__ . "/../../modules/",
]
);
$request = $request->withAttribute("loris", $lorisInstance);

// add baseurl to request attributes
$uri = $request->getURI();
$baseurl = $uri->withPath("")->withQuery("");
$request = $request->withAttribute(
"baseurl",
$baseurl->__toString()
);

//
return $this->next->process($request, $handler);
}
}
48 changes: 20 additions & 28 deletions src/Router/BaseRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,9 @@ class BaseRouter extends PrefixRouter implements RequestHandlerInterface
{
/**
* Construct a BaseRouter
*
* @param \LORIS\LorisInstance $loris The LORIS instance being routed
* @param \User $user The user accessing LORIS. (May be an
* AnonymousUser instance).
*/
public function __construct(
protected \LORIS\LorisInstance $loris,
protected \User $user
) {
public function __construct()
{
}

/**
Expand All @@ -58,16 +52,19 @@ public function handle(ServerRequestInterface $request) : ResponseInterface
$uri = $request->getUri();
$path = $uri->getPath();

// from request attributes
$loris = $request->getAttribute("loris");
$user = $request->getAttribute("user");

// Replace multiple slashes in the URL with a single slash
$path = preg_replace("/\/+/", "/", $path);
// Remove any trailing slash remaining, so that foo/ and foo are the same
// route
$path = preg_replace("/\/$/", "", $path);
$request = $request->withAttribute("user", $this->user)
->withAttribute("loris", $this->loris);
$path = preg_replace("/\/$/", "", $path);

$modulename = null;
if ($path == "") {
if ($this->user instanceof \LORIS\AnonymousUser) {
if ($user instanceof \LORIS\AnonymousUser) {
$modulename = "login";
} else {
$modulename = "dashboard";
Expand All @@ -79,14 +76,14 @@ public function handle(ServerRequestInterface $request) : ResponseInterface
}

$components = [];
if (empty($modulename)) {
if ($modulename === null) {
$components = preg_split("/\/+?/", $path);
$modulename = $components[0];
}

$factory = \NDB_Factory::singleton();
$ehandler = new \LORIS\Middleware\ExceptionHandlingMiddleware();
$logSettings = $this->loris->getConfiguration()->getLogSettings();
$logSettings = $loris->getConfiguration()->getLogSettings();
$exceptionloglevel = $logSettings->getExceptionLogLevel();

if ($exceptionloglevel != "none") {
Expand All @@ -97,7 +94,7 @@ public function handle(ServerRequestInterface $request) : ResponseInterface
$ehandler->setLogger(new \PSR\Log\NullLogger);
}

if ($this->loris->hasModule($modulename)) {
if ($loris->hasModule($modulename)) {
$uri = $request->getURI();
$suburi = $this->stripPrefix($modulename, $uri);

Expand All @@ -110,14 +107,12 @@ public function handle(ServerRequestInterface $request) : ResponseInterface
$baseurl = '';
}
$baseurl = $uri->withPath($baseurl)->withQuery("");
$request = $request->withAttribute("baseurl", $baseurl->__toString());
$factory->setBaseURL((string) $baseurl);

$factory->setBaseURL((string )$baseurl);

$module = $this->loris->getModule($modulename);
$module = $loris->getModule($modulename);
$module->registerAutoloader();

$lang = \LORIS\Middleware\Language::detectLocale($this->loris, $request);
$lang = \LORIS\Middleware\Language::detectLocale($loris, $request);
$request = $request->withAttribute("lang", $lang);

if (file_exists(__DIR__ . "/../../project/locale/")) {
Expand Down Expand Up @@ -168,15 +163,12 @@ public function handle(ServerRequestInterface $request) : ResponseInterface
// FIXME: This should all be one candidates module, not a bunch
// of hacks in the base router.
if (preg_match("/^([0-9]{6,10})$/", $components[0])) {
$baseurl = $uri->withPath("")->withQuery("");

$factory->setBaseURL((string )$baseurl);
$baseurl = $request->getAttribute("baseurl");
$factory->setBaseURL((string) $baseurl);
if (count($components) == 1) {
$request = $request
->withAttribute("baseurl", $baseurl->__toString())
->withAttribute("CandID", $components[0]);
$request = $request->withAttribute("CandID", $components[0]);

$module = $this->loris->getModule("timepoint_list");
$module = $loris->getModule("timepoint_list");
$module->registerAutoloader();

$requestloglevel = $logSettings->getRequestLogLevel();
Expand All @@ -194,7 +186,7 @@ public function handle(ServerRequestInterface $request) : ResponseInterface

// Fall through to 404. We don't have any routes that go farther
// than 1 level..
return (new \LORIS\Middleware\PageDecorationMiddleware($this->user))
return (new \LORIS\Middleware\PageDecorationMiddleware($user))
->process(
$request,
new NoopResponder(new \LORIS\Http\Error($request, 404))
Expand Down
Loading