link user with school

parent 92c499df
......@@ -10,6 +10,7 @@
return [
'modules' => [
'module/application/bootstrap.php',
'module/assets_manager/bootstrap.php',
'module/authentication/bootstrap.php',
'module/authorization/bootstrap.php',
......@@ -19,7 +20,6 @@ return [
'module/sch_inventory/bootstrap.php',
'module/sch_sync/bootstrap.php',
'module/schools/bootstrap.php',
'module/application/bootstrap.php',
],
'cache_config' => 'data/cache/config/settings.php',
];
......@@ -12,6 +12,14 @@ return function (Slim\App $app) {
$container = $app->getContainer();
// setup RedbeanPHP
define('REDBEAN_MODEL_PREFIX', '');
RedBeanPHP\R::setup(
$container['settings']['db']['dsn'],
$container['settings']['db']['user'],
$container['settings']['db']['pass']
);
$container['autoloader']->addPsr4('GrEduLabs\\Application\\', __DIR__ . '/src');
$container['view'] = function ($c) {
......@@ -68,29 +76,19 @@ return function (Slim\App $app) {
};
$events = $container['events'];
$events('on', 'bootstrap', function () use ($container) {
session_name('GrEduLabs');
session_start();
// setup RedbeanPHP
RedBeanPHP\R::setup(
$container['settings']['db']['dsn'],
$container['settings']['db']['user'],
$container['settings']['db']['pass']
);
define('REDBEAN_MODEL_PREFIX', '');
}, 10000000);
}, 100000000000);
$events('on', 'bootstrap', function () use ($container) {
try {
$container['router']->getNamedRoute('user.login')->add('csrf');
} catch (\RuntimeException $e) {
// eat it
foreach ($container['router']->getRoutes() as $route) {
if ('user.login' === $route->getName()) {
$route->add('csrf');
break;
}
}
});
......
......@@ -11,7 +11,6 @@
return function (Slim\App $app) {
$container = $app->getContainer();
$events = $container['events'];
$container['autoloader']->addPsr4('GrEduLabs\\Authentication\\', __DIR__ . '/src');
......@@ -22,7 +21,7 @@ return function (Slim\App $app) {
$container['authentication_adapter'] = function ($c) {
return new GrEduLabs\Authentication\Adapter\RedBeanPHP(
$c['events'],
$c['authentication_identity_class'],
$c['identity_class_resolver'],
$c['authentication_crypt']
);
};
......@@ -34,9 +33,9 @@ return function (Slim\App $app) {
);
};
$container['authentication_identity_class'] = function ($c) {
return GrEduLabs\Authentication\Identity::class;
};
$container['identity_class_resolver'] = $container->protect(function () {
return 'GrEduLabs\\Authentication\\Identity';
});
$container['authentication_crypt'] = function ($c) {
$service = new Zend\Crypt\Password\Bcrypt();
......@@ -50,27 +49,6 @@ return function (Slim\App $app) {
return $service;
};
$events('on', 'bootstrap', function () use ($container) {
$container->extend('view', function ($view, $c) {
$view->getEnvironment()->getLoader()->prependPath(__DIR__ . '/templates');
$view->addExtension(new GrEduLabs\Authentication\Twig\Extension\Identity(
$c['authentication_service']
));
return $view;
});
});
$events('on', 'authenticate.success', function ($stop, $identity) use ($container) {
if (isset($container['logger'])) {
$container['logger']->info(sprintf(
'Authentication through %s for %s',
$identity->authenticationSource,
$identity->mail
));
}
});
$container[GrEduLabs\Authentication\Action\User\Login::class] = function ($c) {
return new GrEduLabs\Authentication\Action\User\Login(
......@@ -90,14 +68,6 @@ return function (Slim\App $app) {
);
};
$app->group('/user', function () {
$this->map(['GET', 'POST'], '/login', GrEduLabs\Authentication\Action\User\Login::class)
->setName('user.login');
$this->get('/logout', GrEduLabs\Authentication\Action\User\Logout::class)
->setName('user.logout');
});
$nav = $container['settings']->get('navigation');
$nav['authentication'] = [
'login' => [
......@@ -113,4 +83,41 @@ return function (Slim\App $app) {
],
];
$container['settings']->set('navigation', $nav);
$events = $container['events'];
$events('on', 'bootstrap', function () use ($app, $container) {
$container->extend('view', function ($view, $c) {
$view->getEnvironment()->getLoader()->prependPath(__DIR__ . '/templates');
$view->addExtension(new GrEduLabs\Authentication\Twig\Extension\Identity(
$c['authentication_service']
));
return $view;
});
$app->group('/user', function () {
$this->map(['GET', 'POST'], '/login', GrEduLabs\Authentication\Action\User\Login::class)
->setName('user.login');
$this->get('/logout', GrEduLabs\Authentication\Action\User\Logout::class)
->setName('user.logout');
});
$app->add(function ($req, $res, $next) use ($container) {
$req = $req->withAttribute('identity', $container['authentication_service']->getIdentity());
return $next($req, $res);
});
});
$events('on', 'authenticate.success', function ($stop, $identity) use ($container) {
if (isset($container['logger'])) {
$container['logger']->info(sprintf(
'Authentication through %s for %s',
$identity->authenticationSource,
$identity->mail
));
}
});
};
......@@ -28,20 +28,20 @@ class RedBeanPHP extends AbstractAdapter
protected $events;
/**
* @var string
* @var callable
*/
protected $identityClass;
protected $resolveIdentityClass;
/**
* @var PasswordInterface
*/
protected $crypt;
public function __construct(callable $events, $identityClass, PasswordInterface $crypt)
public function __construct(callable $events, callable $resolveIdentityClass, PasswordInterface $crypt)
{
$this->events = $events;
$this->identityClass = (string) $identityClass;
$this->crypt = $crypt;
$this->events = $events;
$this->resolveIdentityClass = $resolveIdentityClass;
$this->crypt = $crypt;
}
public function authenticate()
......@@ -69,8 +69,9 @@ class RedBeanPHP extends AbstractAdapter
return new Result(Result::FAILURE_CREDENTIAL_INVALID, null, [self::$failMessage]);
}
$identityClass = $this->identityClass;
$identityClass = call_user_func($this->resolveIdentityClass);
$identity = new $identityClass(
$user->id,
$user->uid,
$user->mail,
$user->displayName,
......
......@@ -14,6 +14,8 @@ use JsonSerializable;
class Identity implements JsonSerializable
{
protected $id;
protected $uid;
protected $mail;
......@@ -24,8 +26,9 @@ class Identity implements JsonSerializable
protected $authenticationSource;
public function __construct($uid, $mail, $displayName, $officeName, $authenticationSource)
public function __construct($id, $uid, $mail, $displayName, $officeName, $authenticationSource)
{
$this->id = $id;
$this->uid = $uid;
$this->mail = $mail;
$this->displayName = $displayName;
......@@ -47,14 +50,15 @@ class Identity implements JsonSerializable
return $this->displayName;
}
public function getUid()
public function getId()
{
return $this->uid;
return $this->id;
}
public function toArray()
{
return [
'id' => $this->id,
'uid' => $this->uid,
'mail' => $this->mail,
'displayName' => $this->displayName,
......
......@@ -44,6 +44,13 @@ return function (Slim\App $app) {
return new GrEduLabs\Authorization\RouteGuard($c[GrEduLabs\Authorization\Acl::class], $role);
};
$container[GrEduLabs\Authorization\Middleware\RoleProvider::class] = function ($c) {
return new GrEduLabs\Authorization\Middleware\RoleProvider(
$c['authentication_service'],
$c[GrEduLabs\Authorization\Acl::class]
);
};
$container[GrEduLabs\Authorization\Listener\RoleProvider::class] = function ($c) {
return new GrEduLabs\Authorization\Listener\RoleProvider(
$c['authentication_storage'],
......@@ -53,15 +60,12 @@ return function (Slim\App $app) {
$events = $container['events'];
$events('on', 'authenticate.success', function ($stop, $identity) use ($container) {
$listener = $container[GrEduLabs\Authorization\Listener\RoleProvider::class];
$listener($stop, $identity);
});
$events('on', 'bootstrap', function () use ($app, $container) {
$container->extend('authentication_identity_class', function ($c) {
return GrEduLabs\Authorization\Identity::class;
$container->extend('identity_class_resolver', function () {
return function () {
return 'GrEduLabs\\Authorization\\Identity';
};
});
$container->extend(GrEduLabs\Application\Twig\Extension\Navigation::class, function ($navigation, $c) {
......@@ -70,6 +74,13 @@ return function (Slim\App $app) {
->setCurrentRole(call_user_func($c['current_role']));
});
foreach ($container['router']->getRoutes() as $route) {
if ('user.login' === $route->getName()) {
$route->add(GrEduLabs\Authorization\Middleware\RoleProvider::class);
break;
}
}
$app->add(GrEduLabs\Authorization\RouteGuard::class);
});
......
......@@ -8,32 +8,42 @@
* @license GNU GPLv3 http://www.gnu.org/licenses/gpl-3.0-standalone.html
*/
namespace GrEduLabs\Authorization\Listener;
namespace GrEduLabs\Authorization\Middleware;
use GrEduLabs\Authorization\RoleAwareInterface;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use RedBeanPHP\R;
use Zend\Authentication\Storage\StorageInterface;
use Zend\Authentication\AuthenticationService;
use Zend\Permissions\Acl\AclInterface;
class RoleProvider
{
private $session;
private $authService;
private $acl;
public function __construct(StorageInterface $session, AclInterface $acl)
public function __construct(AuthenticationService $authService, AclInterface $acl)
{
$this->session = $session;
$this->acl = $acl;
$this->authService = $authService;
$this->acl = $acl;
}
public function __invoke(callable $stop, RoleAwareInterface $identity)
public function __invoke(Request $req, Response $res, callable $next)
{
$user = R::findOne('user', 'mail = ?', [$identity->mail]);
$role = ($user && isset($user->role)) ? $user->role : 'user';
$validRoles = $this->acl->getRoles();
$role = (in_array($role, $validRoles)) ? $role : 'user';
$identity->setRole($role);
$this->session->write($identity);
$res = $next($req, $res);
$identity = $this->authService->getIdentity();
if ($identity && $identity instanceof RoleAwareInterface) {
$user = R::load('user', $identity->id);
$role = ($user && isset($user->role)) ? $user->role : 'user';
$validRoles = $this->acl->getRoles();
$role = (in_array($role, $validRoles)) ? $role : 'user';
$identity->setRole($role);
$this->authService->getStorage()->write($identity);
}
return $res;
}
}
......@@ -68,7 +68,7 @@ return function (Slim\App $app) {
$c['init_cas'],
$c['is_allowed'],
$c['events'],
$c['authentication_identity_class'],
$c['identity_class_resolver'],
$c['router']->pathFor('user.logout.sso')
);
};
......@@ -114,6 +114,11 @@ return function (Slim\App $app) {
}
});
$app->get('/user/login/sso', SchSSO\Action\Login::class)->setName('user.login.sso');
$app->get('/user/logout/sso', SchSSO\Action\Logout::class)->setName('user.logout.sso');
$events('on', 'bootstrap', function () use ($app, $container) {
$app->get('/user/login/sso', SchSSO\Action\Login::class)
->add(GrEduLabs\Authorization\Middleware\RoleProvider::class)
->setName('user.login.sso');
$app->get('/user/logout/sso', SchSSO\Action\Logout::class)
->setName('user.logout.sso');
}, 10);
};
......@@ -34,7 +34,7 @@ class Cas implements AdapterInterface
/**
* @var string
*/
protected $identityClass;
protected $resolveIdentityClass;
/**
* @var string
......@@ -46,14 +46,14 @@ class Cas implements AdapterInterface
callable $initCas,
callable $isAllowed,
callable $events,
$identityClass,
callable $resolveIdentityClass,
$ssoLogoutUrl
) {
$this->initCas = $initCas;
$this->isAllowed = $isAllowed;
$this->events = $events;
$this->identityClass = (string) $identityClass;
$this->ssoLogoutUrl = (string) $ssoLogoutUrl;
$this->initCas = $initCas;
$this->isAllowed = $isAllowed;
$this->events = $events;
$this->resolveIdentityClass = $resolveIdentityClass;
$this->ssoLogoutUrl = (string) $ssoLogoutUrl;
}
public function authenticate()
......@@ -90,8 +90,9 @@ class Cas implements AdapterInterface
return $attributes[$attribute];
};
$identityClass = $this->identityClass;
$identityClass = call_user_func($this->resolveIdentityClass);
$identity = new $identityClass(
null,
$identity,
$filterAttribute('mail'),
$filterAttribute('cn'),
......
......@@ -14,33 +14,36 @@ return function (Slim\App $app) {
$container['autoloader']->addPsr4('SchSync\\', __DIR__ . '/src');
$container[SchSync\Middleware\CreateUser::class] = function ($c) {
return new SchSync\Middleware\CreateUser(
$c['authentication_service'],
$c['router']->pathFor('user.login'),
$c['router']->pathFor('user.logout.sso'),
$c['flash'],
$c['logger']
);
};
$container[SchSync\Middleware\CreateSchool::class] = function ($c) {
return new SchSync\Middleware\CreateSchool(
$c['ldap'],
$c[SchMM\FetchUnit::class],
$c['authentication_service'],
$c['router']->pathFor('user.login'),
$c['router']->pathFor('user.logout.sso'),
$c['flash'],
$c['logger']
);
};
$events = $container['events'];
$events('on', 'bootstrap', function () use ($app, $container) {
$container[SchSync\Middleware\CreateUser::class] = function ($c) {
return new SchSync\Middleware\CreateUser(
$c['authentication_service'],
$c['router']->pathFor('user.login'),
$c['router']->pathFor('user.logout.sso'),
$c['flash'],
$c['logger']
);
};
$container[SchSync\Middleware\CreateSchool::class] = function ($c) {
return new SchSync\Middleware\CreateSchool(
$c['ldap'],
$c[SchMM\FetchUnit::class],
$c['authentication_service'],
$c['router']->pathFor('user.login'),
$c['router']->pathFor('user.logout.sso'),
$c['flash'],
$c['logger']
);
};
$container['router']->getNamedRoute('user.login.sso')
->add(SchSync\Middleware\CreateSchool::class)
->add(SchSync\Middleware\CreateUser::class);
});
$events('on', 'bootstrap', function () use ($container) {
foreach ($container['router']->getRoutes() as $route) {
if ('user.login.sso' === $route->getName()) {
$route->add(SchSync\Middleware\CreateUser::class)
->add(SchSync\Middleware\CreateSchool::class);
break;
}
}
}, -10);
};
......@@ -113,6 +113,7 @@ class CreateSchool
$school = R::findOne('school', 'registry_no = ?', [$registryNo]);
try {
if (!$school) {
R::begin();
$school = R::dispense('school');
$school->registry_no = $unit['registry_no'];
$school->name = $unit['name'];
......@@ -128,10 +129,17 @@ class CreateSchool
$school->eduadmin_id = $unit['edu_admin_id'];
$school->created = time();
$school->creator = $identity->mail;
R::store($school);
$school_id = R::store($school);
$this->logger->info(sprintf('School %s imported from MM to database', $registryNo), ['creator' => $identity->mail]);
$user = R::load('user', $identity->id);
$user->school_id = $school_id;
R::store($user);
$this->logger->info(sprintf('Set school %s to user %s', $registryNo, $identity->mail));
R::commit();
}
} catch (\Exception $e) {
R::rollback();
$this->logger->error(sprintf('Problem inserting school %s form MM in database', $registryNo));
$this->logger->debug('Exception', [$e->getMessage(), $e->getTraceAsString()]);
......
......@@ -15,12 +15,12 @@ use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Log\LoggerInterface;
use RedBeanPHP\R;
use Slim\Flash\Messages;
use Zend\Authentication\AuthenticationServiceInterface;
use Zend\Authentication\AuthenticationService;
class CreateUser
{
/**
* @var AuthenticationServiceInterface
* @var AuthenticationService
*/
private $authService;
......@@ -45,7 +45,7 @@ class CreateUser
private $logger;
public function __construct(
AuthenticationServiceInterface $authService,
AuthenticationService $authService,
$userErrorRedirectUrl,
$ssoLogoutUrl,
Messages $flash,
......@@ -84,7 +84,18 @@ class CreateUser
));
}
$user->last_login = time();
R::store($user);
$user_id = R::store($user);
$identityClass = get_class($identity);
$newIdentity = new $identityClass(
$user_id,
$user->uid,
$user->mail,
$user->display_name,
$user->office_name,
$user->authentication_source
);
$this->authService->getStorage()->write($newIdentity);
} catch (\Exception $e) {
$this->authService->clearIdentity();
$this->flash->addMessage(
......
......@@ -25,6 +25,12 @@ class Index
public function __invoke(Request $req, Response $res, array $args = [])
{
return $this->view->render($res, 'schools/index.twig');
$identity = $req->getAttribute('identity');
$user = \RedBeanPHP\R::load('user', $identity->id);
$school = $user->school;
return $this->view->render($res, 'schools/index.twig', [
'school' => $school->export(),
]);
}
}
......@@ -124,24 +124,7 @@
<div class="col-xs-12 school-container">
{% block schoolContent %}
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent pulvinar tincidunt
odio, vel pretium mauris imperdiet at. In tempor fermentum enim, euismod posuere
purus venenatis sit amet. Sed tincidunt, sapien et varius congue, orci urna rutrum
magna, in porttitor tellus ante nec quam. Praesent non ante commodo, ornare tellus
ut, commodo dolor. Aliquam id laoreet est, sed efficitur erat. Nunc orci diam,
fringilla eu hendrerit sit amet, mollis a risus. Nullam aliquet nisi aliquam ipsum
scelerisque, at convallis augue convallis. In placerat lorem eget lectus maximus,
sed mattis arcu efficitur. Nunc in magna ac neque eleifend sagittis. Quisque non
eros id nibh faucibus posuere. Fusce ut lorem laoreet lacus fermentum tempus at a
ante. Suspendisse luctus libero vel varius fermentum. Suspendisse nec metus odio.</p>
<p>In sapien urna, interdum nec sollicitudin vitae, efficitur et elit. Aliquam erat
volutpat. Aenean a nisl non quam hendrerit condimentum. Sed rhoncus posuere nulla,
vel aliquam orci imperdiet ullamcorper. Morbi vel lacus sem. Donec sit amet eros
eros. Donec sit amet vestibulum nunc. Pellentesque habitant morbi tristique senectus
et netus et malesuada fames ac turpis egestas. Fusce interdum congue nibh accumsan
convallis. Curabitur sit amet orci efficitur, luctus metus ut, euismod enim. Aenean
ultricies arcu nisi, sit amet finibus risus posuere nec. </p>
{{ school.name }}
{% endblock %}
</div>
</div>
......
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