adachsoft / access-control-json-file
JSON file implementation of adachsoft/access-control-contracts.
Package info
gitlab.com/a.adach/access-control-json-file
pkg:composer/adachsoft/access-control-json-file
Requires
- php: ^8.3
- adachsoft/access-control-contracts: ^0.1
Requires (Dev)
- adachsoft/php-code-style: ^0.7.2
- adachsoft/rule-evaluator-expression-language: ^0.1
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.3
- phpunit/phpunit: ^13.4
- rector/rector: ^2.8
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
adachsoft/access-control-json-file implements the repository contracts from adachsoft/access-control-contracts using JSON files. It does not authenticate callers; the host application supplies an AccountId to the access-control services.
Requirements and installation
- PHP 8.3 or later.
- Composer.
adachsoft/access-control-contracts(installed as a runtime dependency).adachsoft/rule-evaluator-expression-languagewhen evaluating conditional grants (install it in the consuming application).
composer require adachsoft/access-control-json-file
composer require adachsoft/rule-evaluator-expression-language
File paths and formats
Configure two writable paths: one for account state and one for the read-only role definitions file. The account repository creates the account file on its first write. The definitions file must exist and contain both required top-level keys; a missing or invalid definition is an error and grants no access. Both files are UTF-8 JSON objects. The account storage uses a sidecar <path>.lock file and atomic replacement when it writes account state.
A definitions file follows the format in docs/spec/access-control.md:
{
"roles": [
{
"id": "developer",
"name": "Developer",
"grants": [
{"permission": "task.create"},
{
"permission": "task.edit",
"condition": "resource.author == actor.id and resource.category == 'TODO'"
},
{"permission": "comment.*"}
]
},
{
"id": "agent",
"name": "Agent",
"grants": [{"permission": "comment.add"}]
}
],
"assignment_rules": [
{"account": "dev_*", "type": "AGENT", "roles": ["developer"]},
{"account": "*", "type": "AGENT", "roles": ["agent"]}
]
}
Assignment rules are evaluated in file order; the first matching rule provisions a new account. Each role and rule must reference valid, unique role identifiers.
The account file is managed by JsonAccountRepository and has this shape:
{
"accounts": [
{
"id": "dev_anna",
"type": "AGENT",
"roles": ["developer"],
"active": true,
"createdAt": "2025-01-01T00:00:00+00:00",
"provisionedBy": "RULE",
"version": 1
}
]
}
createdAt is stored in DateTimeInterface::ATOM format. Each account update uses optimistic version checking; a successful save increments the stored version.
Usage
The repositories can be passed to AccessControlFactory. Conditional grants require a RuleEvaluatorInterface implementation; this example uses adachsoft/rule-evaluator-expression-language:
<?php
declare(strict_types=1);
use AdachSoft\AccessControlContracts\Factory\AccessControlFactory;
use AdachSoft\AccessControlContracts\ValueObject\AccountId;
use AdachSoft\AccessControlJsonFile\Definition\JsonDefinitionFileLoader;
use AdachSoft\AccessControlJsonFile\Repository\JsonAccountRepository;
use AdachSoft\AccessControlJsonFile\Repository\JsonRoleAssignmentRuleRepository;
use AdachSoft\AccessControlJsonFile\Repository\JsonRoleDefinitionRepository;
use AdachSoft\RuleEvaluatorExpressionLanguage\ExpressionLanguageRuleEvaluatorFactory;
$accountsFile = __DIR__ . '/var/access-control/accounts.json';
$definitionsFile = __DIR__ . '/config/access-control.json';
$loader = new JsonDefinitionFileLoader($definitionsFile);
$accounts = new JsonAccountRepository($accountsFile);
$roleDefinitions = new JsonRoleDefinitionRepository($loader);
$assignmentRules = new JsonRoleAssignmentRuleRepository($loader);
$ruleEvaluator = (new ExpressionLanguageRuleEvaluatorFactory())->createDefault();
$accessControl = AccessControlFactory::createAccessDecisionService(
$accounts,
$roleDefinitions,
$assignmentRules,
$ruleEvaluator,
);
$allowed = $accessControl->isGranted(
new AccountId('dev_anna'),
'task.edit',
['author' => 'dev_anna', 'category' => 'TODO'],
);
The first use of an account provisions it according to the first matching assignment rule. Access is denied by default; a conditional grant is effective only when the configured evaluator returns true.
License
This package is licensed under the MIT License, as declared in composer.json.