Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions docs/authentication/adapter.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
### Authentication Adapters
For adapters to define allow/deny (public/protected) per controller action.

#### Built-in adapters

| Adapter | Class | Default file | Notes |
|---------|-------|--------------|-------|
| INI | `TinyAuth\Auth\AllowAdapter\IniAllowAdapter` | `auth_allow.ini` | Default. Zero dependencies. |
| PHP | `TinyAuth\Auth\AllowAdapter\PhpAllowAdapter` | `auth_allow.php` | Returns a plain `return [...]` array. Zero dependencies. |

Switch the adapter via the `allowAdapter` configuration key, e.g.:

```php
'TinyAuth' => [
'allowAdapter' => \TinyAuth\Auth\AllowAdapter\PhpAllowAdapter::class,
'allowFile' => 'auth_allow.php',
],
```

The PHP file uses the same section/value shape as the INI variant — top-level keys are `Plugin.Prefix/Controller` identifiers and values are comma-separated action lists.

#### Custom adapters

Implement the AllowAdapterInterface and make sure your `getAllow()` method returns an array like so:
```php
// normal controller
Expand Down
20 changes: 20 additions & 0 deletions docs/authorization/adapter.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,26 @@
### Authorization Adapters
For RBAC ACL adapters.

#### Built-in adapters

| Adapter | Class | Default file | Notes |
|---------|-------|--------------|-------|
| INI | `TinyAuth\Auth\AclAdapter\IniAclAdapter` | `auth_acl.ini` | Default. Zero dependencies. |
| PHP | `TinyAuth\Auth\AclAdapter\PhpAclAdapter` | `auth_acl.php` | Returns a plain `return [...]` array. Zero dependencies. |

Switch the adapter via the `aclAdapter` configuration key, e.g.:

```php
'TinyAuth' => [
'aclAdapter' => \TinyAuth\Auth\AclAdapter\PhpAclAdapter::class,
'aclFile' => 'auth_acl.php',
],
```

The PHP file uses the same section/key/value shape as the INI variant — top-level keys are `Plugin.Prefix/Controller` identifiers and each section maps action names (or comma-separated action lists) to comma-separated role lists.

#### Custom adapters

Implement the AclAdapterInterface and make sure your `getAcl()` method returns an array like so:
```php
// normal controller
Expand Down
2 changes: 1 addition & 1 deletion docs/guide/custom-adapters.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Custom Adapters

TinyAuth's two INI-based stores (`auth_allow.ini` for public actions, `auth_acl.ini` for role permissions) are just the default backends. You can swap either one out for a database-driven, API-driven, or any other source by implementing a small interface.
TinyAuth ships with two file-based backends (`Ini`, `Php` — see [Authorization Adapters](/authorization/adapter) and [Authentication Adapters](/authentication/adapter)) for the public-action whitelist (`auth_allow.*`) and the role permissions (`auth_acl.*`). If a different format is all you need, just switch the `aclAdapter` / `allowAdapter` config key. You only need a custom adapter when the data has to come from somewhere else entirely — a database, an API, etc.

## When you'd want a custom adapter

Expand Down
108 changes: 108 additions & 0 deletions src/Auth/AclAdapter/AbstractAclAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

namespace TinyAuth\Auth\AclAdapter;

use Cake\Core\Configure;
use TinyAuth\Utility\Utility;

abstract class AbstractAclAdapter implements AclAdapterInterface {

/**
* Loads the raw section => data array from the underlying config source.
*
* The returned shape matches `parse_ini_file($path, true)` — top-level keys are
* section identifiers (e.g. `Tags`, `Plugin.Admin/Tags`) and each value is a
* `actions => roles` map.
*
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @return array<string, array<string, string>>
*/
abstract protected function parseConfig(array $config): array;

/**
* @param array $availableRoles A list of available user roles.
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @return array
*/
public function getAcl(array $availableRoles, array $config): array {
$sections = $this->parseConfig($config);

$acl = [];
foreach ($sections as $key => $array) {
$acl[$key] = Utility::deconstructIniKey($key);
if (Configure::read('debug')) {
$acl[$key]['map'] = $array;
}
$acl[$key]['deny'] = [];
$acl[$key]['allow'] = [];

foreach ($array as $actions => $roles) {
$roles = explode(',', $roles);
$actions = explode(',', $actions);

$deniedRoles = [];
foreach ($roles as $roleId => $role) {
$role = trim($role);
if (!$role) {
continue;
}
$denied = mb_substr($role, 0, 1) === '!';
if ($denied) {
$role = mb_substr($role, 1);
if (!array_key_exists($role, $availableRoles)) {
unset($roles[$roleId]);

continue;
}

unset($roles[$roleId]);
$deniedRoles[] = $role;

continue;
}

if (!array_key_exists($role, $availableRoles) && $role !== '*') {
unset($roles[$roleId]);

continue;
}
if ($role === '*') {
unset($roles[$roleId]);
$roles = array_merge($roles, array_keys($availableRoles));
}
}

foreach ($actions as $action) {
$action = trim($action);
if (!$action) {
continue;
}

foreach ($roles as $role) {
$role = trim($role);
if (!$role) {
continue;
}
$roleName = strtolower($role);

$newRole = $availableRoles[$roleName];
$acl[$key]['allow'][$action][$roleName] = $newRole;
}
foreach ($deniedRoles as $role) {
$role = trim($role);
if (!$role) {
continue;
}
$roleName = strtolower($role);

$newRole = $availableRoles[$roleName];
$acl[$key]['deny'][$action][$roleName] = $newRole;
}
}
}
}

return $acl;
}

}
93 changes: 5 additions & 88 deletions src/Auth/AclAdapter/IniAclAdapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,16 @@

namespace TinyAuth\Auth\AclAdapter;

use Cake\Core\Configure;
use TinyAuth\Utility\Utility;

class IniAclAdapter implements AclAdapterInterface {
class IniAclAdapter extends AbstractAclAdapter {

/**
* {@inheritDoc}
*
* @return array
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @return array<string, array<string, string>>
*/
public function getAcl(array $availableRoles, array $config): array {
$iniArray = Utility::parseFiles($config['filePath'], $config['file']);

$acl = [];
foreach ($iniArray as $key => $array) {
$acl[$key] = Utility::deconstructIniKey($key);
if (Configure::read('debug')) {
$acl[$key]['map'] = $array;
}
$acl[$key]['deny'] = [];
$acl[$key]['allow'] = [];

foreach ($array as $actions => $roles) {
// Get all roles used in the current INI section
$roles = explode(',', $roles);
$actions = explode(',', $actions);

$deniedRoles = [];
foreach ($roles as $roleId => $role) {
$role = trim($role);
if (!$role) {
continue;
}
$denied = mb_substr($role, 0, 1) === '!';
if ($denied) {
$role = mb_substr($role, 1);
if (!array_key_exists($role, $availableRoles)) {
unset($roles[$roleId]);

continue;
}

unset($roles[$roleId]);
$deniedRoles[] = $role;

continue;
}

// Prevent undefined roles appearing in the iniMap
if (!array_key_exists($role, $availableRoles) && $role !== '*') {
unset($roles[$roleId]);

continue;
}
if ($role === '*') {
unset($roles[$roleId]);
$roles = array_merge($roles, array_keys($availableRoles));
}
}

foreach ($actions as $action) {
$action = trim($action);
if (!$action) {
continue;
}

foreach ($roles as $role) {
$role = trim($role);
if (!$role) {
continue;
}
$roleName = strtolower($role);

// Lookup role id by name in roles array
$newRole = $availableRoles[$roleName];
$acl[$key]['allow'][$action][$roleName] = $newRole;
}
foreach ($deniedRoles as $role) {
$role = trim($role);
if (!$role) {
continue;
}
$roleName = strtolower($role);

// Lookup role id by name in roles array
$newRole = $availableRoles[$roleName];
$acl[$key]['deny'][$action][$roleName] = $newRole;
}
}
}
}

return $acl;
protected function parseConfig(array $config): array {
return Utility::parseFiles($config['filePath'], $config['file']);
}

}
38 changes: 38 additions & 0 deletions src/Auth/AclAdapter/PhpAclAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace TinyAuth\Auth\AclAdapter;

use Cake\Core\Exception\CakeException;

class PhpAclAdapter extends AbstractAclAdapter {

/**
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @throws \Cake\Core\Exception\CakeException
* @return array<string, array<string, string>>
*/
protected function parseConfig(array $config): array {
$paths = $config['filePath'] ?? null;
if ($paths === null) {
$paths = ROOT . DS . 'config' . DS;
}

$list = [];
foreach ((array)$paths as $path) {
$file = $path . $config['file'];
if (!file_exists($file)) {
throw new CakeException(sprintf('Missing TinyAuth config file (%s)', $file));
}

$data = include $file;
if (!is_array($data)) {
throw new CakeException(sprintf('Invalid TinyAuth config file (%s)', $file));
}

$list += $data;
}

return $list;
}

}
65 changes: 65 additions & 0 deletions src/Auth/AllowAdapter/AbstractAllowAdapter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php

namespace TinyAuth\Auth\AllowAdapter;

use Cake\Core\Configure;
use TinyAuth\Utility\Utility;

abstract class AbstractAllowAdapter implements AllowAdapterInterface {

/**
* Loads the raw section => actions array from the underlying config source.
*
* The returned shape matches `parse_ini_file($path, false)` — top-level keys
* are section identifiers (e.g. `Users`, `Admin/Users`) and each value is the
* raw comma-separated action list.
*
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @return array<string, string>
*/
abstract protected function parseConfig(array $config): array;

/**
* @param array<string, mixed> $config Current TinyAuth configuration values.
* @return array
*/
public function getAllow(array $config): array {
$sections = $this->parseConfig($config);

$auth = [];
foreach ($sections as $key => $actions) {
$auth[$key] = Utility::deconstructIniKey($key);

$actions = explode(',', $actions);
foreach ($actions as $k => $action) {
$action = trim($action);
if ($action === '') {
unset($actions[$k]);

continue;
}
$actions[$k] = $action;
}

if (Configure::read('debug')) {
$auth[$key]['map'] = $actions;
}
$auth[$key]['deny'] = [];
$auth[$key]['allow'] = [];

foreach ($actions as $action) {
$denied = mb_substr($action, 0, 1) === '!';
if ($denied) {
$auth[$key]['deny'][] = mb_substr($action, 1);

continue;
}

$auth[$key]['allow'][] = $action;
}
}

return $auth;
}

}
Loading
Loading