Redis cache for faster auth

This commit is contained in:
Evann Regnault 2024-06-19 23:41:01 +02:00
parent 3ab65d1c51
commit 7c8e79c199
4 changed files with 36 additions and 2 deletions

View file

@ -4,3 +4,5 @@ keycloak_token_url=https://keycloak.example.com/auth/realms/master/protocol/open
realm=master realm=master
users_path=/srv/dav/public users_path=/srv/dav/public
base_uri=/ base_uri=/
redis_host=localhost
redis_port=6379

View file

@ -6,9 +6,11 @@ This project is meant to be a WebDav Server using Keycloak roles for it's [Princ
## Requirements ## Requirements
- PHP - PHP
- [phpredis](https://github.com/phpredis/phpredis)
- Composer - Composer
- A running keycloak instance - A running keycloak instance
- A Client with `Direct access grants` enabled - A Client with `Direct access grants` enabled
- A running Redis Instance
## Configuration ## Configuration

View file

@ -12,10 +12,14 @@ require 'vendor/autoload.php';
$dotenv = Dotenv::createImmutable(__DIR__); $dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load(); $dotenv->load();
$redis_client = new Redis();
$redis_client->connect($_ENV['redis_host'], intval($_ENV['redis_port']));
$principalBackend = new RolesBackend(); $principalBackend = new RolesBackend();
// Set Auth // Set Auth
$authBackend = new Keycloak\KeycloakAuth($principalBackend,$_ENV['client_id'], $_ENV['client_secret'], $_ENV['keycloak_token_url'] ); $authBackend = new Keycloak\KeycloakAuth($redis_client, $principalBackend,$_ENV['client_id'], $_ENV['client_secret'], $_ENV['keycloak_token_url'] );
$authBackend->setRealm($_ENV['realm']); $authBackend->setRealm($_ENV['realm']);
$authPlugin = new DAV\Auth\Plugin($authBackend); $authPlugin = new DAV\Auth\Plugin($authBackend);

View file

@ -3,27 +3,49 @@
namespace Keycloak; namespace Keycloak;
use Principal\RolesBackend; use Principal\RolesBackend;
use Redis;
use Sabre\DAV\Auth\Backend\AbstractBasic; use Sabre\DAV\Auth\Backend\AbstractBasic;
class KeycloakAuth extends AbstractBasic class KeycloakAuth extends AbstractBasic
{ {
private Redis $redis_client;
private RolesBackend $principal_backend; private RolesBackend $principal_backend;
private string $client_id; private string $client_id;
private string $client_secret; private string $client_secret;
private string $keycloakTokenUrl; private string $keycloakTokenUrl;
public function __construct(RolesBackend $principal_backend, string $client_id, public function __construct(Redis $redis_client, RolesBackend $principal_backend, string $client_id,
string $client_secret, string $keycloakTokenUrl) string $client_secret, string $keycloakTokenUrl)
{ {
$this->redis_client = $redis_client;
$this->principal_backend = $principal_backend; $this->principal_backend = $principal_backend;
$this->client_id = $client_id; $this->client_id = $client_id;
$this->client_secret = $client_secret; $this->client_secret = $client_secret;
$this->keycloakTokenUrl = $keycloakTokenUrl; $this->keycloakTokenUrl = $keycloakTokenUrl;
} }
private function addReditCache(string $username, string $hash, array $roles): void {
$this->redis_client->set("credentials".$username.$hash, json_encode($roles), ["EX" => 60 * 15]);
}
private function checkReditCache(string $username, string $hash): array {
if (!$this->redis_client->exists("credentials" . $username . $hash)) return ["valid" => false];
$datastr = $this->redis_client->get("credentials" . $username . $hash);
$roles = json_decode($datastr);
return ["valid" => true, "roles" => $roles];
}
protected function validateUserPass($username, $password) : bool protected function validateUserPass($username, $password) : bool
{ {
$hash = hash("sha256", $password);
$inCache = $this->checkReditCache($username, $hash);
if ($inCache["valid"]) {
$this->principal_backend->setPrincipals($inCache["roles"]);
return true;
}
$curl = curl_init(); $curl = curl_init();
curl_setopt_array($curl, [ curl_setopt_array($curl, [
@ -52,6 +74,8 @@ class KeycloakAuth extends AbstractBasic
if ($err || $data['http_code'] != 200) { if ($err || $data['http_code'] != 200) {
return false; return false;
} else { } else {
$this->addReditCache($username, $hash, []);
$x = json_decode($body); $x = json_decode($body);
$user_data = json_decode(base64_decode(explode(".",$x->access_token)[1]), true); $user_data = json_decode(base64_decode(explode(".",$x->access_token)[1]), true);
@ -66,6 +90,8 @@ class KeycloakAuth extends AbstractBasic
$this->principal_backend->setPrincipals($roles); $this->principal_backend->setPrincipals($roles);
$this->addReditCache($username, $hash, $roles);
return true; return true;
} }