298 lines
4.8 KiB
PHP
298 lines
4.8 KiB
PHP
<?php
|
|
|
|
namespace alveolata\auth;
|
|
|
|
// require_once(DIR_ALVEOLATA . '/definitions.php');
|
|
require_once(DIR_ALVEOLATA . '/list/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/string/functions.php');
|
|
require_once(DIR_ALVEOLATA . '/session/session.php');
|
|
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class class_exception_policyreport extends \Exception
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
$messages
|
|
)
|
|
{
|
|
parent::__construct(
|
|
' | '.join($messages)
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
abstract class class_policy
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
)
|
|
{
|
|
}
|
|
|
|
|
|
/**
|
|
* @param record<session_id:string> $environment
|
|
* @return list<string>
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
abstract public function check(
|
|
array $environment
|
|
) : array
|
|
;
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class class_policy_none extends class_policy
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
|
|
/**
|
|
* @implementation
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function check(
|
|
array $environment
|
|
) : array
|
|
{
|
|
return [];
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class class_policy_conjunction extends class_policy
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
array $subpolicies
|
|
)
|
|
{
|
|
parent::__construct();
|
|
$this->subpolicies = $subpolicies;
|
|
}
|
|
|
|
|
|
/**
|
|
* @implementation
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function check(
|
|
array $environment
|
|
) : array
|
|
{
|
|
return (
|
|
\alveolata\list_\reduce(
|
|
\alveolata\list_\map(
|
|
$this->subpolicies,
|
|
function ($policy) use ($environment) {
|
|
return $policy->check($environment);
|
|
}
|
|
),
|
|
[],
|
|
function ($x, $y) {return \alveolata\list_\concat($x, $y);}
|
|
)
|
|
);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class class_policy_disjunction extends class_policy
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
array $subpolicies
|
|
)
|
|
{
|
|
parent::__construct();
|
|
$this->subpolicies = $subpolicies;
|
|
}
|
|
|
|
|
|
/**
|
|
* @implementation
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function check(
|
|
array $environment
|
|
) : array
|
|
{
|
|
$some = \alveolata\list_\some(
|
|
$this->subpolicies,
|
|
function ($policy) use ($environment) {
|
|
return $policy->check($environment);
|
|
}
|
|
);
|
|
return ($some ? [] : ['all alternatives failed']);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
class class_policy_logged_in extends class_policy
|
|
{
|
|
|
|
/**
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function __construct(
|
|
)
|
|
{
|
|
parent::__construct();
|
|
}
|
|
|
|
|
|
/**
|
|
* @implementation
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
public function check(
|
|
array $environment
|
|
) : array
|
|
{
|
|
if (! array_key_exists('session_id', $environment)) {
|
|
return ['session id not set'];
|
|
}
|
|
else {
|
|
if (! \alveolata\session\has($environment['session_id'])) {
|
|
return ['no session present'];
|
|
}
|
|
else {
|
|
return [];
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/**
|
|
* @param record<kind:string,parameters:map<strin,any>>
|
|
* @return class_policy
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function make(
|
|
array $description
|
|
) : class_policy
|
|
{
|
|
switch ($description['kind']) {
|
|
default: {
|
|
throw (
|
|
new \Exception(
|
|
\alveolata\string\coin('unhandled policy kind "{{kind}}"', ['kind' => $description['kind']])
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
case 'none': {
|
|
return (
|
|
new class_policy_none(
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
case 'logged_in': {
|
|
return (
|
|
new class_policy_logged_in(
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
case 'conjunction': {
|
|
return (
|
|
new class_policy_conjunction(
|
|
\helper\list_\map(
|
|
$description['parameters']['sub'] ?? [],
|
|
function ($description_) {
|
|
return make($description_);
|
|
}
|
|
)
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
case 'disjunction': {
|
|
return (
|
|
new class_policy_disjunction(
|
|
\helper\list_\map(
|
|
$description['parameters']['sub'] ?? [],
|
|
function ($description_) {
|
|
return make($description_);
|
|
}
|
|
)
|
|
)
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @param class_policy $policy
|
|
* @param function<void,type_result> $function
|
|
* @param record<session_id:string> $environment
|
|
* @return type_result
|
|
* @throw \Exception if the policy check fails
|
|
* @author Christian Fraß <frass@greenscale.de>
|
|
*/
|
|
function wrap/*<type_result>*/(
|
|
class_policy $policy,
|
|
array $environment,
|
|
\Closure $function
|
|
)/* : type_result*/
|
|
{
|
|
$messages = $policy->check($environment);
|
|
if (count($messages) === 0) {
|
|
$result = $function();
|
|
return $result;
|
|
}
|
|
else {
|
|
throw (new class_exception_policyreport($messages));
|
|
}
|
|
}
|
|
|
|
|