1 <?php
namespace Tilmeld;
18 const VERSION =
'1.0.0';
21 const READ_ACCESS = 1;
22 const WRITE_ACCESS = 2;
23 const FULL_ACCESS = 4;
31 public static $config;
39 public static $currentUser =
null;
47 private static $serverTimezone;
59 if (!isset(self::$currentUser)) {
62 return self::$currentUser->gatekeeper($ability);
79 $defaults = include dirname(__DIR__).
'/conf/defaults.php';
80 self::$config = array_replace($defaults, $config);
83 if (!isset(Nymph::$driver)) {
84 throw new Exception(
'Tilmeld can\'t be configured before Nymph.');
97 $user = self::$currentUser;
99 if (isset($user) && $user->gatekeeper(
'system/admin')) {
104 if (!isset($optionsAndSelectors[0])) {
105 throw new Exception(
'No options in argument.');
106 } elseif (isset($optionsAndSelectors[0][
'class'])
108 $optionsAndSelectors[0][
'class'] ===
'\Tilmeld\Entities\User' 109 || $optionsAndSelectors[0][
'class'] ===
'\Tilmeld\Entities\Group' 110 || $optionsAndSelectors[0][
'class'] ===
'Tilmeld\Entities\User' 111 || $optionsAndSelectors[0][
'class'] ===
'Tilmeld\Entities\Group' 118 if ($user ===
null) {
119 $optionsAndSelectors[] = [
'|',
121 'gte' => [
'acOther', Tilmeld::READ_ACCESS],
124 '!isset' => [
'user',
'group']
130 'gte' => [
'acOther', Tilmeld::READ_ACCESS],
140 'ref' => [
'user', $user],
141 'gte' => [
'acUser', Tilmeld::READ_ACCESS]
152 if (isset($user->group) && isset($user->group->guid)) {
154 $groupRefs[] = [
'group', $user->group];
156 $acRefs[] = [
'acRead', $user->group];
157 $acRefs[] = [
'acWrite', $user->group];
158 $acRefs[] = [
'acFull', $user->group];
160 foreach ($user->groups as $curSecondaryGroup) {
161 if (isset($curSecondaryGroup) && isset($curSecondaryGroup->guid)) {
163 $groupRefs[] = [
'group', $curSecondaryGroup];
165 $acRefs[] = [
'acRead', $curSecondaryGroup];
166 $acRefs[] = [
'acWrite', $curSecondaryGroup];
167 $acRefs[] = [
'acFull', $curSecondaryGroup];
170 foreach ($user->getDescendantGroups() as $curDescendantGroup) {
171 if (isset($curDescendantGroup) && isset($curDescendantGroup->guid)) {
173 $groupRefs[] = [
'group', $curDescendantGroup];
175 $acRefs[] = [
'acRead', $curDescendantGroup];
176 $acRefs[] = [
'acWrite', $curDescendantGroup];
177 $acRefs[] = [
'acFull', $curDescendantGroup];
181 if (!empty($groupRefs)) {
183 'gte' => [
'acGroup', Tilmeld::READ_ACCESS],
190 if (!empty($acRefs)) {
195 $optionsAndSelectors[] = $selector;
270 $type = Tilmeld::READ_ACCESS,
274 if (!is_object($entity) || !is_callable([$entity,
'is'])) {
279 if ($user ===
null) {
280 $userOrNull = self::$currentUser;
281 $userOrEmpty = User::current(
true);
282 } elseif ($user ===
false) {
284 $userOrEmpty = User::factory();
286 $userOrNull = $userOrEmpty = $user;
289 if ($userOrEmpty->gatekeeper(
'system/admin')) {
295 is_a($entity,
'\Tilmeld\Entities\User')
296 || is_a($entity,
'\Tilmeld\Entities\Group')
297 || is_a($entity,
'\SciActive\HookOverride_Tilmeld_Entities_User')
298 || is_a($entity,
'\SciActive\HookOverride_Tilmeld_Entities_Group')
301 $type === Tilmeld::READ_ACCESS
302 || $userOrEmpty->gatekeeper(
'tilmeld/admin')
309 if (!isset($entity->user) && !isset($entity->group)) {
314 $acUser = $entity->acUser ?? Tilmeld::FULL_ACCESS;
315 $acGroup = $entity->acGroup ?? Tilmeld::READ_ACCESS;
316 $acOther = $entity->acOther ?? Tilmeld::NO_ACCESS;
318 if ($userOrNull ===
null) {
319 return ($acOther >= $type);
323 if ($userOrEmpty->is($entity)) {
328 if (isset($userOrEmpty->group)
329 && is_callable([$userOrEmpty->group,
'is'])
330 && $userOrEmpty->group->is($entity)
331 && $type === Tilmeld::READ_ACCESS
337 $allGroups = isset($userOrEmpty->group) ? [$userOrEmpty->group] : [];
338 $allGroups = array_merge($allGroups, $userOrEmpty->groups);
339 $allGroups = array_merge($allGroups, $userOrEmpty->getDescendantGroups());
343 [
'type' => Tilmeld::FULL_ACCESS,
'array' => (array) $entity->acFull],
344 [
'type' => Tilmeld::WRITE_ACCESS,
'array' => (array) $entity->acWrite],
345 [
'type' => Tilmeld::READ_ACCESS,
'array' => (array) $entity->acRead]
347 foreach ($checks as $curCheck) {
348 if ($type <= $curCheck[
'type']) {
349 if ($userOrEmpty->inArray($curCheck[
'array'])) {
352 foreach ($allGroups as $curGroup) {
353 if (is_callable([$curGroup,
'inArray'])
354 && $curGroup->inArray($curCheck[
'array'])
363 if (is_callable([$entity->user,
'is'])
364 && $entity->user->is($userOrNull)
366 return ($acUser >= $type);
368 if (is_callable([$entity->group,
'is'])
369 && $entity->group->inArray($allGroups)
371 return ($acGroup >= $type);
373 return ($acOther >= $type);
384 if (!isset(self::$serverTimezone)) {
385 self::$serverTimezone = date_default_timezone_get();
390 isset($user->groups);
391 self::$currentUser = $user;
392 date_default_timezone_set(self::$currentUser->getTimezone());
394 self::$currentUser->updateDataProtection();
395 if (isset(self::$currentUser->group)) {
396 self::$currentUser->group->updateDataProtection();
398 foreach (self::$currentUser->groups as $group) {
399 $group->updateDataProtection();
409 $user = self::$currentUser;
410 self::$currentUser =
null;
411 if (isset(self::$serverTimezone)) {
412 date_default_timezone_set(self::$serverTimezone);
415 $user->updateDataProtection();
426 $extract = self::$config[
'jwt_extract']($token);
430 $guid = $extract[
'guid'];
432 $user = Nymph::getEntity(
433 [
'class' =>
'\Tilmeld\Entities\User'],
438 if (!$user || !$user->guid || !$user->enabled) {
453 if (!empty($_SERVER[
'HTTP_X_TILMELDAUTH']) && empty($_COOKIE[
'TILMELDAUTH'])) {
454 $fromAuthHeader =
true;
455 $authToken = $_SERVER[
'HTTP_X_TILMELDAUTH'];
456 } elseif (!empty($_COOKIE[
'TILMELDAUTH'])) {
457 $fromAuthHeader =
false;
458 $authToken = $_COOKIE[
'TILMELDAUTH'];
462 $setupUrlParts = parse_url(self::$config[
'setup_url']);
463 $setupHost = $setupUrlParts[
'host'].
464 (array_key_exists(
'port', $setupUrlParts) ?
':'.$setupUrlParts[
'port'] :
'');
465 if ($_SERVER[
'HTTP_HOST'] === $setupHost
466 && $_SERVER[
'REQUEST_URI'] === $setupUrlParts[
'path']
469 $extract = self::$config[
'jwt_extract']($authToken);
472 if (empty($_SERVER[
'HTTP_X_XSRF_TOKEN'])) {
476 $extract = self::$config[
'jwt_extract'](
478 $_SERVER[
'HTTP_X_XSRF_TOKEN']
486 $guid = $extract[
'guid'];
487 $expire = $extract[
'expire'];
489 $user = User::factory($guid);
490 if (!$user || !$user->guid || !$user->enabled) {
495 if ($expire < time() + self::$config[
'jwt_renew']) {
498 self::login($user, $fromAuthHeader);
500 self::fillSession($user);
513 public static function login($user, $sendAuthHeader) {
514 if (isset($user->guid) && $user->enabled) {
515 $token = self::$config[
'jwt_builder']($user);
516 $appUrlParts = parse_url(self::$config[
'app_url']);
520 time() + self::$config[
'jwt_expire'],
521 $appUrlParts[
'path'],
522 $appUrlParts[
'host'],
523 $appUrlParts[
'scheme'] ===
'https',
526 if ($sendAuthHeader) {
527 header(
"X-TILMELDAUTH: $token");
529 self::fillSession($user);
539 self::clearSession();
540 $appUrlParts = parse_url(self::$config[
'app_url']);
545 $appUrlParts[
'path'],
565 $caseSensitive =
false,
568 Nymph::hsort($array, $property,
'parent', $caseSensitive, $reverse);
static authenticate()
Check for a TILMELDAUTH cookie, and, if set, authenticate from it.
static fillSession($user)
Fill session user data.
static gatekeeper($ability=null)
Check to see if the current user has an ability.
static extractToken($token)
Validate and extract the user from a token.
static addAccessControlSelectors(&$optionsAndSelectors)
Add selectors to a list of options and selectors which will limit results to only entities the curren...
static checkPermissions(&$entity, $type=Tilmeld::READ_ACCESS, $user=null)
Check an entity's permissions for a user.
static groupSort(&$array, $property=null, $caseSensitive=false, $reverse=false)
Sort an array of groups hierarchically.
static login($user, $sendAuthHeader)
Logs the given user into the system.
static configure($config=[])
Apply configuration to Tilmeld.
static clearSession()
Clear session user data.
static logout()
Logs the current user out of the system.