mirror of
https://github.com/hay-kot/mealie.git
synced 2025-08-22 14:33:33 -07:00
feat: Allow using OICD auth cache instead of session
This commit is contained in:
parent
dd55d23a37
commit
f9294f2634
4 changed files with 63 additions and 1 deletions
|
@ -113,6 +113,7 @@ For usage, see [Usage - OpenID Connect](../authentication/oidc-v2.md)
|
||||||
| OIDC_GROUPS_CLAIM | groups | Optional if not using `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP`. This is the claim Mealie will request from your IdP and will use to compare to `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP` to allow the user to log in to Mealie or is set as an admin. **Your IdP must be configured to grant this claim** |
|
| OIDC_GROUPS_CLAIM | groups | Optional if not using `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP`. This is the claim Mealie will request from your IdP and will use to compare to `OIDC_USER_GROUP` or `OIDC_ADMIN_GROUP` to allow the user to log in to Mealie or is set as an admin. **Your IdP must be configured to grant this claim** |
|
||||||
| OIDC_SCOPES_OVERRIDE | None | Advanced configuration used to override the scopes requested from the IdP. **Most users won't need to change this**. At a minimum, 'openid profile email' are required. |
|
| OIDC_SCOPES_OVERRIDE | None | Advanced configuration used to override the scopes requested from the IdP. **Most users won't need to change this**. At a minimum, 'openid profile email' are required. |
|
||||||
| OIDC_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) |
|
| OIDC_TLS_CACERTFILE | None | File path to Certificate Authority used to verify server certificate (e.g. `/path/to/ca.crt`) |
|
||||||
|
| OIDC_USE_AUTH_CACHE | False | If `True`, OIDC authentication will use server cache instead of session to store its temporary data. |
|
||||||
|
|
||||||
### OpenAI
|
### OpenAI
|
||||||
|
|
||||||
|
|
|
@ -338,6 +338,7 @@ class AppSettings(AppLoggingSettings):
|
||||||
OIDC_GROUPS_CLAIM: str | None = "groups"
|
OIDC_GROUPS_CLAIM: str | None = "groups"
|
||||||
OIDC_SCOPES_OVERRIDE: str | None = None
|
OIDC_SCOPES_OVERRIDE: str | None = None
|
||||||
OIDC_TLS_CACERTFILE: str | None = None
|
OIDC_TLS_CACERTFILE: str | None = None
|
||||||
|
OIDC_USE_AUTH_CACHE: bool = False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def OIDC_REQUIRES_GROUP_CLAIM(self) -> bool:
|
def OIDC_REQUIRES_GROUP_CLAIM(self) -> bool:
|
||||||
|
|
|
@ -19,6 +19,8 @@ from mealie.routes._base.routers import UserAPIRouter
|
||||||
from mealie.schema.user import PrivateUser
|
from mealie.schema.user import PrivateUser
|
||||||
from mealie.schema.user.auth import CredentialsRequestForm
|
from mealie.schema.user.auth import CredentialsRequestForm
|
||||||
|
|
||||||
|
from .auth_cache import AuthCache
|
||||||
|
|
||||||
public_router = APIRouter(tags=["Users: Authentication"])
|
public_router = APIRouter(tags=["Users: Authentication"])
|
||||||
user_router = UserAPIRouter(tags=["Users: Authentication"])
|
user_router = UserAPIRouter(tags=["Users: Authentication"])
|
||||||
logger = root_logger.get_logger("auth")
|
logger = root_logger.get_logger("auth")
|
||||||
|
@ -27,7 +29,10 @@ remember_me_duration = timedelta(days=14)
|
||||||
|
|
||||||
settings = get_app_settings()
|
settings = get_app_settings()
|
||||||
if settings.OIDC_READY:
|
if settings.OIDC_READY:
|
||||||
oauth = OAuth()
|
cache = None
|
||||||
|
if settings.OIDC_USE_AUTH_CACHE:
|
||||||
|
cache = AuthCache()
|
||||||
|
oauth = OAuth(cache=cache)
|
||||||
scope = None
|
scope = None
|
||||||
if settings.OIDC_SCOPES_OVERRIDE:
|
if settings.OIDC_SCOPES_OVERRIDE:
|
||||||
scope = settings.OIDC_SCOPES_OVERRIDE
|
scope = settings.OIDC_SCOPES_OVERRIDE
|
||||||
|
|
55
mealie/routes/auth/auth_cache.py
Normal file
55
mealie/routes/auth/auth_cache.py
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cPickle as pickle
|
||||||
|
except ImportError:
|
||||||
|
import pickle
|
||||||
|
|
||||||
|
|
||||||
|
class AuthCache:
|
||||||
|
def __init__(self, threshold=500, default_timeout=300):
|
||||||
|
self.default_timeout = default_timeout
|
||||||
|
self._cache = {}
|
||||||
|
self.clear = self._cache.clear
|
||||||
|
self._threshold = threshold
|
||||||
|
|
||||||
|
def _prune(self):
|
||||||
|
if len(self._cache) > self._threshold:
|
||||||
|
now = time.time()
|
||||||
|
toremove = []
|
||||||
|
for idx, (key, (expires, _)) in enumerate(self._cache.items()):
|
||||||
|
if (expires != 0 and expires <= now) or idx % 3 == 0:
|
||||||
|
toremove.append(key)
|
||||||
|
for key in toremove:
|
||||||
|
self._cache.pop(key, None)
|
||||||
|
|
||||||
|
def _normalize_timeout(self, timeout):
|
||||||
|
if timeout is None:
|
||||||
|
timeout = self.default_timeout
|
||||||
|
if timeout > 0:
|
||||||
|
timeout = time.time() + timeout
|
||||||
|
return timeout
|
||||||
|
|
||||||
|
async def get(self, key):
|
||||||
|
try:
|
||||||
|
expires, value = self._cache[key]
|
||||||
|
if expires == 0 or expires > time.time():
|
||||||
|
return pickle.loads(value)
|
||||||
|
except (KeyError, pickle.PickleError):
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def set(self, key, value, timeout=None):
|
||||||
|
expires = self._normalize_timeout(timeout)
|
||||||
|
self._prune()
|
||||||
|
self._cache[key] = (expires, pickle.dumps(value, pickle.HIGHEST_PROTOCOL))
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def delete(self, key):
|
||||||
|
return self._cache.pop(key, None) is not None
|
||||||
|
|
||||||
|
async def has(self, key):
|
||||||
|
try:
|
||||||
|
expires, value = self._cache[key]
|
||||||
|
return expires == 0 or expires > time.time()
|
||||||
|
except KeyError:
|
||||||
|
return False
|
Loading…
Add table
Add a link
Reference in a new issue