Commit fe7a4e5b authored by François Agneray's avatar François Agneray

Authorization for search and download routes

parent d16998ed
......@@ -121,7 +121,7 @@ $container->set('App\Action\DatasetFamilyListAction', function (ContainerInterfa
});
$container->set('App\Action\DatasetListByInstanceAction', function (ContainerInterface $c) {
return new App\Action\DatasetListByInstanceAction($c->get('em'));
return new App\Action\DatasetListByInstanceAction($c->get('em'), $c->get(SETTINGS)['token']);
});
$container->set('App\Action\DatasetFamilyAction', function (ContainerInterface $c) {
......@@ -180,10 +180,11 @@ $container->set('App\Action\SearchAction', function (ContainerInterface $c) {
return new App\Action\SearchAction(
$c->get('em'),
new App\Utils\DBALConnectionFactory(),
new App\Utils\Operator\OperatorFactory()
new App\Utils\Operator\OperatorFactory(),
$c->get(SETTINGS)['token']
);
});
$container->set('App\Action\DownloadFileAction', function (ContainerInterface $c) {
return new App\Action\DownloadFileAction($c->get('em'));
return new App\Action\DownloadFileAction($c->get('em'), $c->get(SETTINGS)['token']);
});
......@@ -13,6 +13,9 @@ declare(strict_types=1);
namespace App\Action;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Exception\HttpUnauthorizedException;
use Slim\Exception\HttpForbiddenException;
/**
* Centralize access to the database and some common functions
......@@ -49,4 +52,35 @@ abstract class AbstractAction
{
return !isset($parsedBody[$field]);
}
/**
* @param Request $request
* @param string $datasetName
* @param string $adminRole
*/
protected function verifyDatasetAuthorization(Request $request, string $datasetName, string $adminRole)
{
$token = $request->getAttribute('token');
if (!$token) {
// The user is not connected (401)
throw new HttpUnauthorizedException($request);
}
$roles = $token->getClaim('realm_access')->roles;
if (!in_array($adminRole, $roles)) {
$qb = $this->em->createQueryBuilder();
$qb->select('d.name')
->from('App\Entity\Group', 'g')
->join('g.datasets', 'd')
->where($qb->expr()->in('g.role', $roles))
->andWhere($qb->expr()->eq('d.name', ':dname'));
$qb->setParameter('dname', $datasetName);
$r = $qb->getQuery()->getResult();
if (count($r) < 1) {
throw new HttpForbiddenException(
$request,
'You do not have the permission to access the dataset : ' . $datasetName
);
}
}
}
}
......@@ -14,10 +14,30 @@ namespace App\Action;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Doctrine\ORM\EntityManagerInterface;
use Slim\Exception\HttpNotFoundException;
final class DatasetListByInstanceAction extends AbstractAction
{
/**
* Contains settings to handle Json Web Token
*
* @var array
*/
private $settings;
/**
* Create the classe before call __invoke to execute the action
*
* @param EntityManagerInterface $em Doctrine Entity Manager Interface
* @param array $settings Settings about token
*/
public function __construct(EntityManagerInterface $em, array $settings)
{
parent::__construct($em);
$this->settings = $settings;
}
/**
* `GET` Returns a list of all datasets for a given instance
*
......@@ -52,21 +72,23 @@ final class DatasetListByInstanceAction extends AbstractAction
->join('d.datasetFamily', 'f')
->where($qb->expr()->eq('IDENTITY(f.instance)', ':instanceName'));
if (!$token) {
// If user is not connected return public datasets
$qb->andWhere($qb->expr()->eq('d.public', 'true'));
} else {
$roles = $token->getClaim('realm_access')->roles;
if (!in_array('anis_admin', $roles)) {
// If user is not an admin return public datasets
// And returns datasets from user's groups
if (boolval($this->settings['enabled'])) {
if (!$token) {
// If user is not connected return public datasets
$qb->andWhere($qb->expr()->eq('d.public', 'true'));
$qb2 = $this->em->createQueryBuilder();
$qb2->select('d2.name')
->from('App\Entity\Group', 'g')
->join('g.datasets', 'd2')
->where($qb2->expr()->in('g.role', $roles));
$qb->orWhere($qb->expr()->in('d.name', $qb2->getDQL()));
} else {
$roles = $token->getClaim('realm_access')->roles;
if (!in_array($this->settings['admin_role'], $roles)) {
// If user is not an admin return public datasets
// And returns datasets from user's groups
$qb->andWhere($qb->expr()->eq('d.public', 'true'));
$qb2 = $this->em->createQueryBuilder();
$qb2->select('d2.name')
->from('App\Entity\Group', 'g')
->join('g.datasets', 'd2')
->where($qb2->expr()->in('g.role', $roles));
$qb->orWhere($qb->expr()->in('d.name', $qb2->getDQL()));
}
}
}
......
......@@ -14,11 +14,31 @@ namespace App\Action;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Message\ResponseInterface as Response;
use Doctrine\ORM\EntityManagerInterface;
use Slim\Exception\HttpNotFoundException;
use Nyholm\Psr7\Factory\Psr17Factory;
final class DownloadFileAction extends AbstractAction
{
/**
* Contains settings to handle Json Web Token
*
* @var array
*/
private $settings;
/**
* Create the classe before call __invoke to execute the action
*
* @param EntityManagerInterface $em Doctrine Entity Manager Interface
* @param array $settings Settings about token
*/
public function __construct(EntityManagerInterface $em, array $settings)
{
parent::__construct($em);
$this->settings = $settings;
}
/**
* `GET` Returns the file found
*
......@@ -45,6 +65,11 @@ final class DownloadFileAction extends AbstractAction
);
}
// If dataset is private and authorization enabled
if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
$this->verifyDatasetAuthorization($request, $dataset->getName(), $this->settings['admin_role']);
}
// Search the file
$filePath = realpath($dataset->getDataPath()) . DIRECTORY_SEPARATOR . $args['fpath'];
......
......@@ -36,21 +36,31 @@ final class SearchAction extends AbstractAction
{
private $connectionFactory;
private $operatorFactory;
/**
* Contains settings to handle Json Web Token
*
* @var array
*/
private $settings;
/**
* Create the classe before call __invoke to execute the action
*
* @param EntityManagerInterface $em Doctrine Entity Manager Interface
* @param DBALConnectionFactory $connectionFactory Factory used to construct connection to business database
* @param array $settings Settings about token
*/
public function __construct(
EntityManagerInterface $em,
DBALConnectionFactory $connectionFactory,
OperatorFactory $operatorFactory
OperatorFactory $operatorFactory,
array $settings
) {
parent::__construct($em);
$this->connectionFactory = $connectionFactory;
$this->operatorFactory = $operatorFactory;
$this->settings = $settings;
}
/**
......@@ -79,6 +89,11 @@ final class SearchAction extends AbstractAction
);
}
// If dataset is private and authorization enabled
if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
$this->verifyDatasetAuthorization($request, $dataset->getName(), $this->settings['admin_role']);
}
// Create query builder with from clause using dataset information
$connection = $this->connectionFactory->create($dataset->getProject()->getDatabase());
$queryBuilder = $connection->createQueryBuilder();
......
......@@ -49,7 +49,7 @@ final class AdminMiddleware implements MiddlewareInterface
public function process(Request $request, RequestHandler $handler): Response
{
if ($request->getMethod() === OPTIONS || $this->settings['enabled'] === 0) {
if ($request->getMethod() === OPTIONS || !boolval($this->settings['enabled'])) {
return $handler->handle($request);
}
......
......@@ -62,7 +62,7 @@ final class AuthorizationMiddleware implements MiddlewareInterface
if (
$request->getMethod() === OPTIONS
|| !$request->hasHeader('Authorization')
|| $this->settings['enabled'] === 0
|| !boolval($this->settings['enabled'])
) {
return $handler->handle($request);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment