Merge pull request #9211 from appwrite/add-user-types

Update audits to include user type
This commit is contained in:
Christy Jacob 2025-01-21 12:41:23 +05:30 committed by GitHub
commit b4e1101a9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 52 additions and 6 deletions

View file

@ -188,13 +188,14 @@ App::init()
->inject('request') ->inject('request')
->inject('dbForPlatform') ->inject('dbForPlatform')
->inject('dbForProject') ->inject('dbForProject')
->inject('queueForAudits')
->inject('project') ->inject('project')
->inject('user') ->inject('user')
->inject('session') ->inject('session')
->inject('servers') ->inject('servers')
->inject('mode') ->inject('mode')
->inject('team') ->inject('team')
->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) { ->action(function (App $utopia, Request $request, Database $dbForPlatform, Database $dbForProject, Audit $queueForAudits, Document $project, Document $user, ?Document $session, array $servers, string $mode, Document $team) {
$route = $utopia->getRoute(); $route = $utopia->getRoute();
if ($project->isEmpty()) { if ($project->isEmpty()) {
@ -246,9 +247,10 @@ App::init()
$user = new Document([ $user = new Document([
'$id' => '', '$id' => '',
'status' => true, 'status' => true,
'type' => Auth::ACTIVITY_TYPE_APP,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(), 'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '', 'password' => '',
'name' => $project->getAttribute('name', 'Untitled'), 'name' => 'Dynamic Key',
]); ]);
$role = Auth::USER_ROLE_APPS; $role = Auth::USER_ROLE_APPS;
@ -256,6 +258,8 @@ App::init()
Authorization::setRole(Auth::USER_ROLE_APPS); Authorization::setRole(Auth::USER_ROLE_APPS);
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys. Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
$queueForAudits->setUser($user);
} }
} elseif ($keyType === API_KEY_STANDARD) { } elseif ($keyType === API_KEY_STANDARD) {
// No underline means no prefix. Backwards compatibility. // No underline means no prefix. Backwards compatibility.
@ -267,9 +271,10 @@ App::init()
$user = new Document([ $user = new Document([
'$id' => '', '$id' => '',
'status' => true, 'status' => true,
'type' => Auth::ACTIVITY_TYPE_APP,
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(), 'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '', 'password' => '',
'name' => $project->getAttribute('name', 'Untitled'), 'name' => $key->getAttribute('name', 'UNKNOWN'),
]); ]);
$role = Auth::USER_ROLE_APPS; $role = Auth::USER_ROLE_APPS;
@ -304,6 +309,8 @@ App::init()
$dbForPlatform->purgeCachedDocument('projects', $project->getId()); $dbForPlatform->purgeCachedDocument('projects', $project->getId());
} }
} }
$queueForAudits->setUser($user);
} }
} }
} }
@ -511,8 +518,15 @@ App::init()
->setIP($request->getIP()) ->setIP($request->getIP())
->setHostname($request->getHostname()) ->setHostname($request->getHostname())
->setEvent($route->getLabel('audits.event', '')) ->setEvent($route->getLabel('audits.event', ''))
->setProject($project) ->setProject($project);
->setUser($user);
/* If a session exists, use the user associated with the session */
if (!$user->isEmpty()) {
$userClone = clone $user;
// $user doesn't support `type` and can cause unintended effects.
$userClone->setAttribute('type', Auth::ACTIVITY_TYPE_USER);
$queueForAudits->setUser($userClone);
}
$queueForDeletes->setProject($project); $queueForDeletes->setProject($project);
$queueForDatabase->setProject($project); $queueForDatabase->setProject($project);
@ -720,10 +734,32 @@ App::shutdown()
} }
if (!$user->isEmpty()) { if (!$user->isEmpty()) {
$userClone = clone $user;
// $user doesn't support `type` and can cause unintended effects.
$userClone->setAttribute('type', Auth::ACTIVITY_TYPE_USER);
$queueForAudits->setUser($userClone);
} elseif ($queueForAudits->getUser() === null || $queueForAudits->getUser()->isEmpty()) {
/**
* User in the request is empty, and no user was set for auditing previously.
* This indicates:
* - No API Key was used.
* - No active session exists.
*
* Therefore, we consider this an anonymous request and create a relevant user.
*/
$user = new Document([
'$id' => '',
'status' => true,
'type' => Auth::ACTIVITY_TYPE_GUEST,
'email' => 'guest.' . $project->getId() . '@service.' . $request->getHostname(),
'password' => '',
'name' => 'Guest',
]);
$queueForAudits->setUser($user); $queueForAudits->setUser($user);
} }
if (!empty($queueForAudits->getResource()) && !empty($queueForAudits->getUser()->getId())) { if (!empty($queueForAudits->getResource()) && !$queueForAudits->getUser()->isEmpty()) {
/** /**
* audits.payload is switched to default true * audits.payload is switched to default true
* in order to auto audit payload for all endpoints * in order to auto audit payload for all endpoints

View file

@ -43,6 +43,13 @@ class Auth
public const USER_ROLE_APPS = 'apps'; public const USER_ROLE_APPS = 'apps';
public const USER_ROLE_SYSTEM = 'system'; public const USER_ROLE_SYSTEM = 'system';
/**
* Activity associated with user or the app.
*/
public const ACTIVITY_TYPE_APP = 'app';
public const ACTIVITY_TYPE_USER = 'user';
public const ACTIVITY_TYPE_GUEST = 'guest';
/** /**
* Token Types. * Token Types.
*/ */

View file

@ -2,6 +2,7 @@
namespace Appwrite\Platform\Workers; namespace Appwrite\Platform\Workers;
use Appwrite\Auth\Auth;
use Exception; use Exception;
use Throwable; use Throwable;
use Utopia\Audit\Audit; use Utopia\Audit\Audit;
@ -60,6 +61,7 @@ class Audits extends Action
$userName = $user->getAttribute('name', ''); $userName = $user->getAttribute('name', '');
$userEmail = $user->getAttribute('email', ''); $userEmail = $user->getAttribute('email', '');
$userType = $user->getAttribute('type', Auth::ACTIVITY_TYPE_USER);
$audit = new Audit($dbForProject); $audit = new Audit($dbForProject);
$audit->log( $audit->log(
@ -74,6 +76,7 @@ class Audits extends Action
'userId' => $user->getId(), 'userId' => $user->getId(),
'userName' => $userName, 'userName' => $userName,
'userEmail' => $userEmail, 'userEmail' => $userEmail,
'userType' => $userType,
'mode' => $mode, 'mode' => $mode,
'data' => $auditPayload, 'data' => $auditPayload,
] ]