feat: add role override for admins

This commit is contained in:
Christy Jacob
2024-07-24 02:47:46 +04:00
parent eea5d610ba
commit c167201d7c
5 changed files with 98 additions and 25 deletions
+2
View File
@@ -416,6 +416,8 @@ App::post('/v1/databases')
$databaseId = $databaseId == 'unique()' ? ID::unique() : $databaseId;
var_dump($databaseId);
try {
$dbForProject->createDocument('databases', new Document([
'$id' => $databaseId,
+2 -1
View File
@@ -3,6 +3,7 @@
use Appwrite\Auth\Auth;
use Appwrite\Auth\MFA\Type\TOTP;
use Appwrite\Auth\Validator\Phone;
use Appwrite\Auth\Validator\Role as ValidatorRole;
use Appwrite\Detector\Detector;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
@@ -386,7 +387,7 @@ App::post('/v1/teams/:teamId/memberships')
->param('email', '', new Email(), 'Email of the new team member.', true)
->param('userId', '', new UID(), 'ID of the user to be added to a team.', true)
->param('phone', '', new Phone(), 'Phone number. Format this number with a leading \'+\' and a country code, e.g., +16175551212.', true)
->param('roles', [], new ArrayList(new Key(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
->param('roles', [], new ArrayList(new ValidatorRole(), APP_LIMIT_ARRAY_PARAMS_SIZE), 'Array of strings. Use this param to set the user roles in the team. A role can be any string. Learn more about [roles and permissions](https://appwrite.io/docs/permissions). Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' roles are allowed, each 32 characters long.')
->param('url', '', fn ($clients) => new Host($clients), 'URL to redirect the user back to your app from the invitation email. This parameter is not required when an API key is supplied. Only URLs from hostnames in your project platform list are allowed. This requirement helps to prevent an [open redirect](https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html) attack against your project API.', true, ['clients']) // TODO add our own built-in confirm page
->param('name', '', new Text(128), 'Name of the new team member. Max length: 128 chars.', true)
->inject('response')
+23 -18
View File
@@ -166,17 +166,14 @@ App::init()
}
/** Default role */
$roles = Config::getParam('roles', []);
$role = ($user->isEmpty())
? Role::guests()->toString()
: Role::users()->toString();
/** Allowed Scopes for the role */
$roles = Config::getParam('roles', []);
$scopes = $roles[$role]['scopes'];
var_dump("Mode : " . $mode);
var_dump(Auth::getRoles($user));
/**
* API Key Authentication
*/
@@ -235,7 +232,7 @@ App::init()
/**
* Admin User Authentication
*/
elseif (APP_MODE_ADMIN === $mode && $project->getId() !== 'console') {
elseif (APP_MODE_ADMIN === $mode) {
if ($user->isEmpty()) {
throw new Exception(Exception::USER_UNAUTHORIZED);
}
@@ -248,7 +245,7 @@ App::init()
$adminRoles = [];
$memberships = $user->getAttribute('memberships', []);
foreach ($memberships as $membership) {
if ($membership->getAttribute('teamId') === $teamId) {
if ($membership->getAttribute('confirm', false) === true && $membership->getAttribute('teamId') === $teamId) {
$adminRoles = $membership->getAttribute('roles', []);
break;
}
@@ -258,26 +255,34 @@ App::init()
throw new Exception(Exception::USER_UNAUTHORIZED);
}
/** Get scopes available to that role for this project */
foreach ($adminRoles as $role) {
$scopes = \array_merge($scopes, $roles[$role]['scopes']);
}
$adminRoles = array_filter($adminRoles, function ($role) use ($project) {
return str_contains($role, $project->getId()) || str_contains($role, 'projects/all') || str_contains($role, 'owner');
});
// Authorization::setRole(Auth::USER_ROLE_ADMIN);
// foreach ($membership['roles'] as $memberRole) {
// Authorization::setRole($memberRole);
// if (empty($adminRoles)) {
// throw new Exception(Exception::USER_UNAUTHORIZED);
// }
Authorization::setRole(Auth::USER_ROLE_DEVELOPER);
Authorization::setDefaultStatus(false);
var_dump("####### ADMIN ROLES #######");
var_dump($adminRoles);
foreach ($adminRoles as $adminRole) {
if (str_contains($adminRole, 'owner')) {
$role = Auth::USER_ROLE_OWNER;
$scopes = \array_merge($scopes, $roles[$role]['scopes']);
break;
}
$parts = explode('/', $adminRole);
$role = $parts[2] ?? Auth::USER_ROLE_GUESTS;
$scopes = \array_merge($scopes, $roles[$role]['scopes']);
}
Authorization::setDefaultStatus(false); // Cancel security segmentation for admin users.
}
$scopes = \array_unique($scopes);
var_dump("##### Admin Scopes ######");
var_dump($scopes);
Authorization::setRole($role);
foreach (Auth::getRoles($user) as $authRole) {
Authorization::setRole($authRole);
}
-6
View File
@@ -1169,9 +1169,6 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
Auth::$unique = $session['id'] ?? '';
Auth::$secret = $session['secret'] ?? '';
var_dump("####### Session ID ##########");
var_dump(Auth::$unique);
if (APP_MODE_ADMIN !== $mode) {
if ($project->isEmpty()) {
$user = new Document([]);
@@ -1186,9 +1183,6 @@ App::setResource('user', function ($mode, $project, $console, $request, $respons
$user = $dbForConsole->getDocument('users', Auth::$unique);
}
var_dump("####### User ##########");
var_dump($user);
if (
$user->isEmpty() // Check a document has been found in the DB
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)
+71
View File
@@ -0,0 +1,71 @@
<?php
namespace Appwrite\Auth\Validator;
use Utopia\Validator;
class Role extends Validator
{
/**
* @var string
*/
protected string $message = '';
/**
* Get Description.
*
* Returns validator description
*
* @return string
*/
public function getDescription(): string
{
return $this->message;
}
/**
* Expression constructor
*/
public function __construct()
{
}
/**
* Is valid.
*
* Returns true if valid or false if not.
*
* @param $value
*
* @return bool
*/
public function isValid($value): bool
{
return true;
}
/**
* Is array
*
* Function will return true if object is array.
*
* @return bool
*/
public function isArray(): bool
{
return false;
}
/**
* Get Type
*
* Returns validator type.
*
* @return string
*/
public function getType(): string
{
return self::TYPE_STRING;
}
}