1
0
Fork 0
mirror of synced 2024-09-29 08:51:28 +13:00

feat: Adding Authentication injection for user id and secret

This commit is contained in:
Binyamin Yawitz 2024-06-28 14:33:13 -04:00
parent 034814c924
commit 6f62f915d9
No known key found for this signature in database
7 changed files with 102 additions and 50 deletions

@ -1 +1 @@
Subproject commit 5169fe16d63066f64ab5013c78953aea04e24b53
Subproject commit f483d9631d6f21e94aedb20b5c37c56fea06c23e

View file

@ -2,6 +2,7 @@
use Ahc\Jwt\JWT;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Authentication;
use Appwrite\Auth\MFA\Challenge;
use Appwrite\Auth\MFA\Type;
use Appwrite\Auth\MFA\Type\TOTP;
@ -399,14 +400,15 @@ Http::get('/v1/account/sessions')
->inject('user')
->inject('locale')
->inject('authorization')
->action(function (Response $response, Document $user, Locale $locale, Authorization $authorization) {
->inject('authentication')
->action(function (Response $response, Document $user, Locale $locale, Authorization $authorization, Authentication $authentication) {
$roles = $authorization->getRoles();
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
$isAppUser = Auth::isAppUser($roles);
$sessions = $user->getAttribute('sessions', []);
$current = Auth::sessionVerify($sessions, Auth::$secret);
$current = Auth::sessionVerify($sessions, $authentication->getSecret());
foreach ($sessions as $key => $session) {/** @var Document $session */
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
@ -445,7 +447,8 @@ Http::delete('/v1/account/sessions')
->inject('locale')
->inject('queueForEvents')
->inject('queueForDeletes')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Delete $queueForDeletes) {
->inject('authentication')
->action(function (Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Delete $queueForDeletes, Authentication $authentication) {
$protocol = $request->getProtocol();
$sessions = $user->getAttribute('sessions', []);
@ -461,7 +464,7 @@ Http::delete('/v1/account/sessions')
->setAttribute('current', false)
->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')));
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) {
if ($session->getAttribute('secret') == Auth::hash($authentication->getSecret())) {
$session->setAttribute('current', true);
// If current session delete the cookies too
@ -507,7 +510,8 @@ Http::get('/v1/account/sessions/:sessionId')
->inject('user')
->inject('locale')
->inject('authorization')
->action(function (?string $sessionId, Response $response, Document $user, Locale $locale, Authorization $authorization) {
->inject('authentication')
->action(function (?string $sessionId, Response $response, Document $user, Locale $locale, Authorization $authorization, Authentication $authentication) {
$roles = $authorization->getRoles();
$isPrivilegedUser = Auth::isPrivilegedUser($roles);
@ -515,7 +519,7 @@ Http::get('/v1/account/sessions/:sessionId')
$sessions = $user->getAttribute('sessions', []);
$sessionId = ($sessionId === 'current')
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
? Auth::sessionVerify($user->getAttribute('sessions'), $authentication->getSecret())
: $sessionId;
foreach ($sessions as $session) {/** @var Document $session */
@ -523,7 +527,7 @@ Http::get('/v1/account/sessions/:sessionId')
$countryName = $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown'));
$session
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash(Auth::$secret)))
->setAttribute('current', ($session->getAttribute('secret') == Auth::hash($authentication->getSecret())))
->setAttribute('countryName', $countryName)
->setAttribute('secret', ($isPrivilegedUser || $isAppUser) ? $session->getAttribute('secret', '') : '')
;
@ -558,11 +562,12 @@ Http::delete('/v1/account/sessions/:sessionId')
->inject('locale')
->inject('queueForEvents')
->inject('queueForDeletes')
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Delete $queueForDeletes) {
->inject('authentication')
->action(function (?string $sessionId, ?\DateTime $requestTimestamp, Request $request, Response $response, Document $user, Database $dbForProject, Locale $locale, Event $queueForEvents, Delete $queueForDeletes, Authentication $authentication) {
$protocol = $request->getProtocol();
$sessionId = ($sessionId === 'current')
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
? Auth::sessionVerify($user->getAttribute('sessions'), $authentication->getSecret())
: $sessionId;
$sessions = $user->getAttribute('sessions', []);
@ -581,7 +586,7 @@ Http::delete('/v1/account/sessions/:sessionId')
$session->setAttribute('current', false);
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
if ($session->getAttribute('secret') == Auth::hash($authentication->getSecret())) { // If current session delete the cookies too
$session
->setAttribute('current', true)
->setAttribute('countryName', $locale->getText('countries.' . strtolower($session->getAttribute('countryCode')), $locale->getText('locale.country.unknown')));
@ -636,10 +641,11 @@ Http::patch('/v1/account/sessions/:sessionId')
->inject('dbForProject')
->inject('project')
->inject('queueForEvents')
->action(function (?string $sessionId, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents) {
->inject('authentication')
->action(function (?string $sessionId, Response $response, Document $user, Database $dbForProject, Document $project, Event $queueForEvents, Authentication $authentication) {
$sessionId = ($sessionId === 'current')
? Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret)
? Auth::sessionVerify($user->getAttribute('sessions'), $authentication->getSecret())
: $sessionId;
$sessions = $user->getAttribute('sessions', []);
@ -1142,7 +1148,8 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect')
->inject('geodb')
->inject('queueForEvents')
->inject('authorization')
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization) use ($oauthDefaultSuccess) {
->inject('authentication')
->action(function (string $provider, string $code, string $state, string $error, string $error_description, Request $request, Response $response, Document $project, Document $user, Database $dbForProject, Reader $geodb, Event $queueForEvents, Authorization $authorization, Authentication $authentication) use ($oauthDefaultSuccess) {
$protocol = $request->getProtocol();
$callback = $protocol . '://' . $request->getHostname() . '/v1/account/sessions/oauth2/callback/' . $provider . '/' . $project->getId();
$defaultState = ['success' => $project->getAttribute('url', ''), 'failure' => ''];
@ -1279,7 +1286,7 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect')
}
$sessions = $user->getAttribute('sessions', []);
$current = Auth::sessionVerify($sessions, Auth::$secret);
$current = Auth::sessionVerify($sessions, $authentication->getSecret());
if ($current) { // Delete current session of new one.
$currentDocument = $dbForProject->getDocument('sessions', $current);
@ -2369,14 +2376,15 @@ Http::post('/v1/account/jwt')
->inject('response')
->inject('user')
->inject('dbForProject')
->action(function (Response $response, Document $user, Database $dbForProject) {
->inject('authentication')
->action(function (Response $response, Document $user, Database $dbForProject, Authentication $authentication) {
$sessions = $user->getAttribute('sessions', []);
$current = new Document();
foreach ($sessions as $session) { /** @var Utopia\Database\Document $session */
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
if ($session->getAttribute('secret') == Auth::hash($authentication->getSecret())) { // If current session delete the cookies too
$current = $session;
}
}
@ -4197,7 +4205,8 @@ Http::post('/v1/account/targets/push')
->inject('response')
->inject('dbForProject')
->inject('authorization')
->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization) {
->inject('authentication')
->action(function (string $targetId, string $identifier, string $providerId, Event $queueForEvents, Document $user, Request $request, Response $response, Database $dbForProject, Authorization $authorization, Authentication $authentication) {
$targetId = $targetId == 'unique()' ? ID::unique() : $targetId;
$provider = $authorization->skip(fn () => $dbForProject->getDocument('providers', $providerId));
@ -4213,7 +4222,7 @@ Http::post('/v1/account/targets/push')
$device = $detector->getDevice();
$sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret);
$sessionId = Auth::sessionVerify($user->getAttribute('sessions'), $authentication->getSecret());
$session = $dbForProject->getDocument('sessions', $sessionId);
try {

View file

@ -2,6 +2,7 @@
use Ahc\Jwt\JWT;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Authentication;
use Appwrite\Event\Build;
use Appwrite\Event\Delete;
use Appwrite\Event\Event;
@ -1532,7 +1533,8 @@ Http::post('/v1/functions/:functionId/executions')
->inject('queueForFunctions')
->inject('geodb')
->inject('authorization')
->action(function (string $functionId, string $body, bool $async, string $path, string $method, array $headers, Response $response, Document $project, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode, Func $queueForFunctions, Reader $geodb, Authorization $authorization) {
->inject('authentication')
->action(function (string $functionId, string $body, bool $async, string $path, string $method, array $headers, Response $response, Document $project, Database $dbForProject, Document $user, Event $queueForEvents, Usage $queueForUsage, string $mode, Func $queueForFunctions, Reader $geodb, Authorization $authorization, Authentication $authentication) {
$function = $authorization->skip(fn () => $dbForProject->getDocument('functions', $functionId));
@ -1583,7 +1585,7 @@ Http::post('/v1/functions/:functionId/executions')
foreach ($sessions as $session) {
/** @var Utopia\Database\Document $session */
if ($session->getAttribute('secret') == Auth::hash(Auth::$secret)) { // If current session delete the cookies too
if ($session->getAttribute('secret') == Auth::hash($authentication->getSecret())) { // If current session delete the cookies too
$current = $session;
}
}

View file

@ -5,6 +5,7 @@ require_once __DIR__ . '/../vendor/autoload.php';
use Ahc\Jwt\JWT;
use Ahc\Jwt\JWTException;
use Appwrite\Auth\Auth;
use Appwrite\Auth\Authentication;
use Appwrite\Event\Audit;
use Appwrite\Event\Build;
use Appwrite\Event\Certificate;
@ -423,8 +424,9 @@ $getProjectDB = new Dependency();
$dbForProject = new Dependency();
$dbForConsole = new Dependency();
$queueForUsage = new Dependency();
$authorization = new Dependency();
$queueForMails = new Dependency();
$authorization = new Dependency();
$authentication = new Dependency();
$queueForBuilds = new Dependency();
$deviceForLocal = new Dependency();
$deviceForFiles = new Dependency();
@ -470,7 +472,8 @@ $user
->inject('dbForProject')
->inject('dbForConsole')
->inject('authorization')
->setCallback(function (string $mode, Document $project, Document $console, Request $request, Response $response, Database $dbForProject, Database $dbForConsole, Authorization $authorization) {
->inject('authentication')
->setCallback(function (string $mode, Document $project, Document $console, Request $request, Response $response, Database $dbForProject, Database $dbForConsole, Authorization $authorization, Authentication $authentication) {
$authorization->setDefaultStatus(true);
Auth::setCookieName('a_session_' . $project->getId());
@ -509,26 +512,26 @@ $user
$session = Auth::decodeSession(((isset($fallback[Auth::$cookieName])) ? $fallback[Auth::$cookieName] : ''));
}
Auth::$unique = $session['id'] ?? '';
Auth::$secret = $session['secret'] ?? '';
$authentication->setUnique($session['id'] ?? '');
$authentication->setSecret($session['secret'] ?? '');
if (APP_MODE_ADMIN !== $mode) {
if ($project->isEmpty()) {
$user = new Document([]);
} else {
if ($project->getId() === 'console') {
$user = $dbForConsole->getDocument('users', Auth::$unique);
$user = $dbForConsole->getDocument('users', $authentication->getUnique());
} else {
$user = $dbForProject->getDocument('users', Auth::$unique);
$user = $dbForProject->getDocument('users', $authentication->getUnique());
}
}
} else {
$user = $dbForConsole->getDocument('users', Auth::$unique);
$user = $dbForConsole->getDocument('users', $authentication->getUnique());
}
if (
$user->isEmpty() // Check a document has been found in the DB
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret)
|| !Auth::sessionVerify($user->getAttribute('sessions', []), $authentication->getSecret())
) { // Validate user has valid login token
$user = new Document([]);
}
@ -577,14 +580,16 @@ $session
->setName('session')
->inject('user')
->inject('project')
->setCallback(function (Document $user, Document $project) {
->inject('authorization')
->inject('authentication')
->setCallback(function (Document $user, Document $project, Authorization $authorization, Authentication $authentication) {
if ($user->isEmpty()) {
return;
}
$sessions = $user->getAttribute('sessions', []);
$authDuration = $project->getAttribute('auths', [])['duration'] ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
$sessionId = Auth::sessionVerify($user->getAttribute('sessions'), Auth::$secret, $authDuration);
$sessionId = Auth::sessionVerify($user->getAttribute('sessions'), $authentication->getSecret(), $authDuration);
if (!$sessionId) {
return;
@ -784,6 +789,12 @@ $authorization
return new Authorization();
});
$authentication
->setName('authentication')
->setCallback(function (): Authentication {
return new Authentication();
});
$registry
->setName('registry')
->setCallback(function () use (&$global): Registry {
@ -1259,9 +1270,10 @@ $container->set($localeCodes);
$container->set($dbForProject);
$container->set($dbForConsole);
$container->set($getProjectDB);
$container->set($authorization);
$container->set($queueForUsage);
$container->set($queueForMails);
$container->set($authorization);
$container->set($authentication);
$container->set($schemaVariable);
$container->set($queueForBuilds);
$container->set($queueForEvents);

View file

@ -483,6 +483,7 @@ $server->onMessage(function (int $connection, string $message) use ($server, $co
$projectId = $realtime->connections[$connection]['projectId'];
$database = $container->get('dbForConsole');
$authorization = $container->get('authorization');
$authentication = $container->get('authentication');
if ($projectId !== 'console') {
@ -525,14 +526,15 @@ $server->onMessage(function (int $connection, string $message) use ($server, $co
}
$session = Auth::decodeSession($message['data']['session']);
Auth::$unique = $session['id'] ?? '';
Auth::$secret = $session['secret'] ?? '';
$user = $database->getDocument('users', Auth::$unique);
$authentication->setUnique($session['id'] ?? '');
$authentication->setSecret($session['secret'] ?? '');
$user = $database->getDocument('users', $authorization->getUnique());
if (
empty($user->getId()) // Check a document has been found in the DB
|| !Auth::sessionVerify($user->getAttribute('sessions', []), Auth::$secret) // Validate user has valid login token
|| !Auth::sessionVerify($user->getAttribute('sessions', []), $authentication->getSecret()) // Validate user has valid login token
) {
// cookie not valid
throw new Exception(Exception::REALTIME_MESSAGE_FORMAT_INVALID, 'Session is not valid.');

View file

@ -96,20 +96,6 @@ class Auth
*/
public static $cookieName = 'a_session';
/**
* User Unique ID.
*
* @var string
*/
public static $unique = '';
/**
* User Secret Key.
*
* @var string
*/
public static $secret = '';
/**
* Set Cookie Name.
*

View file

@ -0,0 +1,41 @@
<?php
namespace Appwrite\Auth;
class Authentication
{
/**
* User Unique ID.
*
* @var string
*/
private $unique = '';
/**
* User Secret Key.
*
* @var string
*/
private $secret = '';
public function getUnique(): string
{
return $this->unique;
}
public function setUnique(string $unique): void
{
$this->unique = $unique;
}
public function getSecret(): string
{
return $this->secret;
}
public function setSecret(string $secret): void
{
$this->secret = $secret;
}
}