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
124 changes: 35 additions & 89 deletions src/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,17 @@ class Auth implements AuthInterface
private string $sessionHash;

/**
* @param RudraInterface $rudra
* @param RudraInterface $rudra
* @return void
* @throws \RuntimeException
*/
public function __construct(private readonly RudraInterface $rudra)
{
$remoteAddr = $rudra->request()?->server()?->get("REMOTE_ADDR") ?? '';
$userAgent = $rudra->request()?->server()?->get("HTTP_USER_AGENT") ?? '';
$secret = $rudra->config()?->get("secret") ?? throw new \RuntimeException('Auth secret is missing');

/**
* --------------------------------------------
* Sets the cookie lifetime, session hash
* --------------------------------------------
* Устанавливает время жизни cookie, хэш сессии
* --------------------------------------------
*/
// Sets the cookie lifetime, session hash
$this->expireTime = strtotime('+1 week');
$this->sessionHash = hash_hmac(
algo: 'sha256',
Expand All @@ -50,6 +46,7 @@ public function __construct(private readonly RudraInterface $rudra)
* @param array{0: string, 1: string} $redirect // [0]: 'admin' (успех), [1]: 'login' (ошибка)
* @param array{error: string} $notice
* @return void
* @throws LogicException
*/
#[\Override]
public function authentication(array $user, string $password,
Expand Down Expand Up @@ -80,9 +77,6 @@ public function authentication(array $user, string $password,
}

/**
* @param array $user
* @param string $token
* @return void
* @codeCoverageIgnore
*/
private function setCookiesIfSetRememberMe(array $user, string $token): void
Expand All @@ -109,21 +103,12 @@ private function setCookiesIfSetRememberMe(array $user, string $token): void
);
}

/**
* @param array $user
* @param string $token
* @return void
*/
private function setAuthenticationSession(array $user, string $token): void
{
$this->rudra->session()->set("token", $token);
$this->rudra->session()->set("user", $user);
}

/**
* @param string $redirect
* @return void
*/
#[\Override]
public function logout(string $redirect = ""): void
{
Expand All @@ -135,7 +120,6 @@ public function logout(string $redirect = ""): void
}

/**
* @return void
* @codeCoverageIgnore
*/
private function unsetRememberMeCookie(): void
Expand All @@ -153,47 +137,24 @@ private function unsetRememberMeCookie(): void
}
}

/**
* @param string|null $token
* @param string|null $redirect
* @return bool
*/
#[\Override]
public function authorization(?string $token = null, ?string $redirect = null): bool
{
if (!$this->rudra->session()->has("token")) {
return false;
}

/**
* ---------------------------------------
* Providing access to shared resources
* ---------------------------------------
* Предоставление доступа к общим ресурсам
* ---------------------------------------
*/
// Providing access to shared resources
if ($token === null) {
return true;
}

/**
* -----------------------------------------------------
* Providing access to the user's personal resources
* -----------------------------------------------------
* Предоставление доступа к личным ресурсам пользователя
* -----------------------------------------------------
*/
// Providing access to the user's personal resources
if (hash_equals($token, $this->rudra->session()->get("token"))) {
return true;
}

/**
* -------------------
* If not logged in
* -------------------
* Если не авторизован
* -------------------
*/
// If not logged in
if ($redirect !== null) {
$this->handleRedirect($redirect, ["status" => "Access denied"]);
return false;
Expand All @@ -203,23 +164,18 @@ public function authorization(?string $token = null, ?string $redirect = null):
}

/**
* @param string $role
* @param string $privilege
* @param string|null $redirect
* @return bool
* @throws \InvalidArgumentException
*/
#[\Override]
public function roleBasedAccess(string $role, string $privilege, ?string $redirect = null): bool
{
$roles = $this->rudra->config()->get("roles");

/**
* -------------------------------------------------------------------
* Roles: the smaller the number, the higher the privilege (1 > 2 > 3)
* -------------------------------------------------------------------
* Роли: чем меньше число, тем выше привилегия (1 > 2 > 3)
* -------------------------------------------------------------------
*/
if (!isset($roles[$role], $roles[$privilege])) {
throw new \InvalidArgumentException("Role '{$role}' or '{$privilege}' not found in config");
}

// Roles: the smaller the number, the higher the privilege (1 > 2 > 3)
if ($roles[$role] <= $roles[$privilege]) {
return true;
}
Expand All @@ -233,8 +189,6 @@ public function roleBasedAccess(string $role, string $privilege, ?string $redire
}

/**
* @param string $redirect
* @return void
* @codeCoverageIgnore
*/
public function restoreSessionIfSetRememberMe(string $redirect = "login"): void
Expand Down Expand Up @@ -263,23 +217,12 @@ public function restoreSessionIfSetRememberMe(string $redirect = "login"): void
$this->handleRedirect($redirect, ['status' => 'Authorization data expired']);
}

/**
* @param string $password
* @param int $cost
* @return string
*/
#[\Override]
public function bcrypt(string $password, int $cost = 10): string
{
return password_hash($password, PASSWORD_BCRYPT, ['cost' => $cost]);
}


/**
* @param string $redirect
* @param array $jsonResponse
* @return void
*/
private function handleRedirect(string $redirect, array $jsonResponse): void
{
if ($redirect === 'API') {
Expand All @@ -290,42 +233,45 @@ private function handleRedirect(string $redirect, array $jsonResponse): void
$this->rudra->get(Redirect::class)->run($redirect);
}

/**
* @return string
*/
public function getSessionHash(): string
{
return $this->sessionHash;
}

/**
* @param string $data
* @param string $secret
* @return string
*/
private function encrypt(string $data, string $secret): string
{
$ciphering = 'AES-128-CTR';
$iv = $this->rudra->config()->get('secret');
$result = openssl_encrypt($data, $ciphering, $secret, 0, $iv);

if ($result === false) {
$ivLength = openssl_cipher_iv_length($ciphering);
$iv = random_bytes($ivLength);

$ciphertext = openssl_encrypt($data, $ciphering, $secret, OPENSSL_RAW_DATA, $iv);
if ($ciphertext === false) {
throw new \RuntimeException('Encryption failed');
}

return $result;
return base64_encode($iv . $ciphertext);
}

/**
* @param string $data
* @param string $secret
* @return string
* @throws \RuntimeException
*/
private function decrypt(string $data, string $secret): string
{
$binary = base64_decode($data, true);
if ($binary === false) {
throw new \RuntimeException('Invalid encrypted data (base64 decode failed)');
}

$ciphering = 'AES-128-CTR';
$iv = $this->rudra->config()->get('secret');
$result = openssl_decrypt($data, $ciphering, $secret, 0, $iv);
$ivLength = openssl_cipher_iv_length($ciphering);

if (strlen($binary) < $ivLength) {
throw new \RuntimeException('Encrypted data too short');
}

$iv = substr($binary, 0, $ivLength);
$ciphertext = substr($binary, $ivLength);
$result = openssl_decrypt($ciphertext, $ciphering, $secret, OPENSSL_RAW_DATA, $iv);

if ($result === false) {
throw new \RuntimeException('Decryption failed');
Expand Down
31 changes: 0 additions & 31 deletions src/AuthInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,9 @@

interface AuthInterface
{
/**
* @param array $user
* @param string $password
* @param array $redirect
* @param array $notice
* @return void
*/
public function authentication(array $user, string $password, array $redirect = ['admin', 'login'], array $notice = ["error" => "Wrong access data"]): void;

/**
* @param string $redirect
* @return void
*/
public function logout(string $redirect = ""): void;

/**
* @param string|null $token
* @param string|null $redirect
* @return bool
*/
public function authorization(?string $token = null, ?string $redirect = null): bool;

/**
* @param string $role
* @param string $privilege
* @param string|null $redirect
* @return bool
*/
public function roleBasedAccess(string $role, string $privilege, ?string $redirect = null): bool;

/**
* @param string $password
* @param integer $cost
* @return string
*/
public function bcrypt(string $password, int $cost = 10): string;
}
2 changes: 1 addition & 1 deletion tests/AuthTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* @author Korotkov Danila (Jagepard) <jagepard@yandex.ru>
* @license https://mozilla.org/MPL/2.0/ MPL-2.0
*
* phpunit src/tests/AuthTest --coverage-html src/tests/coverage-html
* phpunit tests/AuthTest --coverage-html src/tests/coverage-html
*/

namespace Rudra\Auth\Tests;
Expand Down
Loading