* some stuff moved to UtilityModule(old DoctrineExpressiveModule)

* api auth in place
This commit is contained in:
Danyi Dávid
2018-05-12 00:14:34 +02:00
parent 68bf4735ad
commit 8cd607b063
48 changed files with 766 additions and 29 deletions

View File

@@ -7,6 +7,7 @@ namespace App\Handler\Api;
use App\Service\AwardeeManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use UtilityModule\Handler\AbstractCrudHandler;
use Zend\Diactoros\Response\JsonResponse;
class AwardeeHandler extends AbstractCrudHandler

View File

@@ -7,6 +7,7 @@ namespace App\Handler\Api;
use App\Service\JudgeManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use UtilityModule\Handler\AbstractCrudHandler;
use Zend\Diactoros\Response\JsonResponse;
class JudgesHandler extends AbstractCrudHandler

View File

@@ -7,6 +7,7 @@ namespace App\Handler\Api;
use App\Service\YearManager;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use UtilityModule\Handler\AbstractCrudHandler;
use Zend\Diactoros\Response\JsonResponse;
class YearsHandler extends AbstractCrudHandler

View File

@@ -6,7 +6,7 @@ namespace App\Service;
use App\Entity\Awardee;
use Doctrine\ORM\EntityManager;
use DoctrineExpressiveModule\Hydrator\DoctrineObject;
use UtilityModule\Hydrator\DoctrineObject;
class AwardeeManager
{

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Service;
use Doctrine\ORM\EntityManager;
use DoctrineExpressiveModule\Hydrator\DoctrineObject;
use UtilityModule\Hydrator\DoctrineObject;
use Psr\Container\ContainerInterface;
class AwardeeManagerFactory

View File

@@ -6,7 +6,7 @@ namespace App\Service;
use App\Entity\Judge;
use Doctrine\ORM\EntityManager;
use DoctrineExpressiveModule\Hydrator\DoctrineObject;
use UtilityModule\Hydrator\DoctrineObject;
class JudgeManager
{

View File

@@ -5,7 +5,7 @@ declare(strict_types=1);
namespace App\Service;
use Doctrine\ORM\EntityManager;
use DoctrineExpressiveModule\Hydrator\DoctrineObject;
use UtilityModule\Hydrator\DoctrineObject;
use Psr\Container\ContainerInterface;
class JudgeManagerFactory

View File

@@ -0,0 +1,34 @@
<?php
namespace UtilityModule\Command;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use UtilityModule\Service\AuthService;
class GeneratePasswordHash extends Command
{
/** @var AuthService */
private $authService;
public function __construct(AuthService $authService)
{
$this->authService = $authService;
parent::__construct();
}
protected function configure()
{
$this->setName('password:generate')
->setDescription('Generate a password hash')
->addArgument('password', InputArgument::REQUIRED, 'Password to hash');
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$pass = $input->getArgument('password');
$output->writeln($this->authService->createPasswordHash($pass));
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace UtilityModule\Command;
use Psr\Container\ContainerInterface;
use UtilityModule\Service\AuthService;
class GeneratePasswordHashFactory
{
/**
* @param ContainerInterface $container
* @return GeneratePasswordHash
*/
public function __invoke(ContainerInterface $container)
{
$authService = $container->get(AuthService::class);
return new GeneratePasswordHash($authService);
}
}

View File

@@ -2,8 +2,10 @@
declare(strict_types=1);
namespace DoctrineExpressiveModule;
namespace UtilityModule;
use Tuupola\Middleware\CorsMiddleware;
use Tuupola\Middleware\JwtAuthentication;
use Zend\EventManager\EventManager;
/**
@@ -25,6 +27,7 @@ class ConfigProvider
return [
'dependencies' => $this->getDependencies(),
'form_elements' => $this->getFormElements(),
'console' => $this->getConsoleCommands(),
];
}
@@ -42,7 +45,15 @@ class ConfigProvider
EventManager::class => EventManager::class,
],
'factories' => [
Command\GeneratePasswordHash::class => Command\GeneratePasswordHashFactory::class,
Hydrator\DoctrineObject::class => Hydrator\DoctrineObjectFactory::class,
CorsMiddleware::class => Middleware\CorsMiddlewareFactory::class,
JwtAuthentication::class => Middleware\JwtMiddlewareFactory::class,
Handler\AuthHandler::class => Handler\AuthHandlerFactory::class,
Service\AuthService::class => Service\AuthServiceFactory::class,
],
];
}
@@ -61,4 +72,13 @@ class ConfigProvider
],
];
}
public function getConsoleCommands(): array
{
return [
'commands' => [
Command\GeneratePasswordHash::class,
]
];
}
}

View File

@@ -1,6 +1,6 @@
<?php
namespace DoctrineExpressiveModule\Form\Element;
namespace UtilityModule\Form\Element;
use Interop\Container\ContainerInterface;

View File

@@ -1,6 +1,6 @@
<?php
namespace DoctrineExpressiveModule\Form\Element\Exception;
namespace UtilityModule\Form\Element\Exception;
use InvalidArgumentException;

View File

@@ -1,6 +1,6 @@
<?php
namespace DoctrineExpressiveModule\Form\Element;
namespace UtilityModule\Form\Element;
use DoctrineModule\Form\Element\Proxy;
use Zend\Form\Element\MultiCheckbox;

View File

@@ -1,8 +1,8 @@
<?php
namespace DoctrineExpressiveModule\Form\Element;
namespace UtilityModule\Form\Element;
use DoctrineExpressiveModule\Form\Element\Proxy;
use UtilityModule\Form\Element\Proxy;
use Zend\Form\Element\Radio as RadioElement;
use Zend\Form\Form;

View File

@@ -1,8 +1,8 @@
<?php
namespace DoctrineExpressiveModule\Form\Element;
namespace UtilityModule\Form\Element;
use DoctrineExpressiveModule\Form\Element\Proxy;
use UtilityModule\Form\Element\Proxy;
use Zend\Form\Element\Select as SelectElement;
use Zend\Form\Form;
use Zend\Stdlib\ArrayUtils;

View File

@@ -1,6 +1,6 @@
<?php
namespace DoctrineExpressiveModule\Form\Element;
namespace UtilityModule\Form\Element;
use Traversable;
use ReflectionMethod;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace App\Handler\Api;
namespace UtilityModule\Handler;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace UtilityModule\Handler;
use Doctrine\ORM\NoResultException;
use Psr\Http\Message\ServerRequestInterface;
use UtilityModule\Service\AuthService;
use Zend\Diactoros\Response\JsonResponse;
class AuthHandler extends AbstractCrudHandler
{
/** @var AuthService */
private $authService;
public function __construct(AuthService $authService) {
$this->authService = $authService;
}
/**
* Respond to POST (login) requests
* @param ServerRequestInterface $request
* @return \Zend\Diactoros\Response\JsonResponse
*/
public function create(ServerRequestInterface $request)
{
$data = $this->getRequestData($request);
try {
return new JsonResponse($this->authService->authenticate(
$data['user'],
$data['pass']
));
} catch (NoResultException $e) {
return new JsonResponse("Access denied", 401);
}
}
/**
* Respond to GET (renew-token) requests
* @param ServerRequestInterface $request
* @return \Zend\Diactoros\Response\JsonResponse
*/
public function get(ServerRequestInterface $request)
{
$token = $request->getAttribute('token');
return new JsonResponse($this->authService->renewToken($token));
}
}

View File

@@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
namespace UtilityModule\Handler;
use Psr\Container\ContainerInterface;
use Psr\Http\Server\RequestHandlerInterface;
use UtilityModule\Service\AuthService;
class AuthHandlerFactory
{
public function __invoke(ContainerInterface $container) : RequestHandlerInterface
{
$authService = $container->get(AuthService::class);
return new AuthHandler($authService);
}
}

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator;
namespace UtilityModule\Hydrator;
use DateTime;
use Doctrine\Common\Persistence\Mapping\ClassMetadata;

View File

@@ -1,6 +1,6 @@
<?php
namespace DoctrineExpressiveModule\Hydrator;
namespace UtilityModule\Hydrator;
use Interop\Container\ContainerInterface;

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Filter;
namespace UtilityModule\Hydrator\Filter;
use Zend\Hydrator\Filter\FilterInterface;

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Strategy;
namespace UtilityModule\Hydrator\Strategy;
use InvalidArgumentException;
use Doctrine\Common\Collections\Collection;

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Strategy;
namespace UtilityModule\Hydrator\Strategy;
/**
* When this strategy is used for Collections, if the new collection does not contain elements that are present in

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Strategy;
namespace UtilityModule\Hydrator\Strategy;
use Doctrine\Common\Collections\Collection;
use LogicException;

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Strategy;
namespace UtilityModule\Hydrator\Strategy;
/**
* When this strategy is used for Collections, if the new collection does not contain elements that are present in

View File

@@ -17,7 +17,7 @@
* <http://www.doctrine-project.org>.
*/
namespace DoctrineExpressiveModule\Hydrator\Strategy;
namespace UtilityModule\Hydrator\Strategy;
use Doctrine\Common\Collections\Collection;
use LogicException;

View File

@@ -2,7 +2,7 @@
declare(strict_types=1);
namespace DoctrineExpressiveModule\Middleware;
namespace UtilityModule\Middleware;
use Psr\Container\ContainerInterface;
use Tuupola\Middleware\CorsMiddleware;

View File

@@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
namespace UtilityModule\Middleware;
use Psr\Container\ContainerInterface;
use Psr\Http\Message\ResponseInterface;
use Tuupola\Middleware\JwtAuthentication;
use Zend\Config\Config;
use Zend\Diactoros\Response\JsonResponse;
use Zend\Expressive\Application;
use Zend\Expressive\Router\Route;
class JwtMiddlewareFactory
{
/** @var Config */
private $aclConfig;
/**
* @param ContainerInterface $container
* @return JwtAuthentication
*/
public function __invoke(ContainerInterface $container): JwtAuthentication
{
$configArray = $container->get('config');
/** @var Config $config */
$config = new Config($configArray);
$this->aclConfig = $config->get('acl_config');
return new JwtAuthentication([
"secret" => $this->aclConfig->get('hmac_key'),
"path" => "/api",
"ignore" => $this->getIgnoredRoutes($container),
"secure" => true,
"relaxed" => [
"localhost",
"granprize.dev.yvan.hu",
],
"error" => function (ResponseInterface $response, $arguments) {
$data["status"] = "error";
$data["message"] = $arguments["message"];
return new JsonResponse($data, 401);
}
]);
}
/**
* @param ContainerInterface $container
* @return array
*/
private function getIgnoredRoutes(ContainerInterface $container): array
{
$passThroughRoutes = [];
/** @var Application $app */
$app = $container->get(Application::class);
$appRoutes = $app->getRoutes();
$unguardedRoutes = $this->aclConfig->get('unguarded_routes', new Config([]))->toArray();
/** @var Route $route */
foreach ($appRoutes as $route) {
if (in_array($route->getName(), $unguardedRoutes)) {
$passThroughRoutes[] = $route->getPath();
}
}
return $passThroughRoutes;
}
}

View File

@@ -0,0 +1,97 @@
<?php
namespace UtilityModule\Service;
use Doctrine\ORM\NoResultException;
use Firebase\JWT\JWT;
use Zend\Config\Config;
use Zend\Crypt\Password\Bcrypt;
class AuthService
{
const CONFIG_KEY_NAME = 'hmac_key';
const PASSWORD_COST = 14;
/**
* @var Config
*/
private $config;
public function __construct(
Config $config
) {
$this->config = $config;
}
/**
* @param string $user
* @param string $pass
* @return string
* @throws NoResultException
*/
public function authenticate(string $user, string $pass): string
{
$cfgUser = $this->config->get('user');
$cfgPass = $this->config->get('pass');
$crypt = new Bcrypt();
$crypt->setCost(self::PASSWORD_COST);
if ($cfgUser===$user && $crypt->verify($pass, $cfgPass)) {
return $this->generateJwt();
}
throw new NoResultException();
}
/**
* @param $token
* @return string
*/
public function renewToken($token): string
{
return $this->renewJWT($token);
}
/**
* @return string
*/
private function generateJwt(): string
{
/** @var string $hmacKey */
$hmacKey = $this->config->get('hmac_key');
return JWT::encode([
"iat" => time(),
"nbf" => time(),
"exp" => time() + 3600,
], $hmacKey);
}
/**
* @param $token
* @return string
*/
private function renewJWT($token): string
{
/** @var string $hmacKey */
$hmacKey = $this->config->get('hmac_key');
return JWT::encode([
"jti" => $token->jti,
"iat" => time(),
"nbf" => time(),
"exp" => time() + 3600,
], $hmacKey);
}
/**
* @param string $password
* @return string
*/
public function createPasswordHash(string $password): string
{
$crypt = new Bcrypt();
$crypt->setCost(self::PASSWORD_COST);
return $crypt->create($password);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace UtilityModule\Service;
use Interop\Container\ContainerInterface;
use Zend\Config\Config;
class AuthServiceFactory
{
/**
* @param ContainerInterface $container
* @return AuthService
*/
public function __invoke(ContainerInterface $container): AuthService
{
$configArr = $container->get('config')['acl_config'];
return new AuthService(new Config($configArr));
}
}