mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
api: Move cookie session management logic to the authenticator for more flexibility
This commit is contained in:
parent
83f7721fdd
commit
f49f03d11e
3 changed files with 66 additions and 3 deletions
|
@ -34,7 +34,6 @@
|
|||
#############################
|
||||
_global:
|
||||
namespace: yunohost
|
||||
cookie_name: yunohost.admin
|
||||
authentication:
|
||||
api: ldap_admin
|
||||
cli: null
|
||||
|
|
|
@ -8,10 +8,14 @@ import time
|
|||
|
||||
from moulinette import m18n
|
||||
from moulinette.authentication import BaseAuthenticator
|
||||
from yunohost.utils.error import YunohostError
|
||||
from moulinette.utils.text import random_ascii
|
||||
|
||||
from yunohost.utils.error import YunohostError, YunohostAuthenticationError
|
||||
|
||||
logger = logging.getLogger("yunohost.authenticators.ldap_admin")
|
||||
|
||||
session_secret = random_ascii()
|
||||
|
||||
|
||||
class Authenticator(BaseAuthenticator):
|
||||
|
||||
|
@ -66,3 +70,57 @@ class Authenticator(BaseAuthenticator):
|
|||
# Free the connection, we don't really need it to keep it open as the point is only to check authentication...
|
||||
if con:
|
||||
con.unbind_s()
|
||||
|
||||
def set_session_cookie(self, infos):
|
||||
|
||||
from bottle import response
|
||||
|
||||
assert isinstance(infos, dict)
|
||||
|
||||
# This allows to generate a new session id or keep the existing one
|
||||
current_infos = self.get_session_cookie(raise_if_no_session_exists=False)
|
||||
new_infos = {"id": current_infos["id"]}
|
||||
new_infos.update(infos)
|
||||
|
||||
response.set_cookie(
|
||||
"yunohost.admin",
|
||||
new_infos,
|
||||
secure=True,
|
||||
secret=session_secret,
|
||||
httponly=True,
|
||||
# samesite="strict", # Bottle 0.12 doesn't support samesite, to be added in next versions
|
||||
)
|
||||
|
||||
def get_session_cookie(self, raise_if_no_session_exists=True):
|
||||
|
||||
from bottle import request
|
||||
|
||||
try:
|
||||
# N.B. : here we implicitly reauthenticate the cookie
|
||||
# because it's signed via the session_secret
|
||||
# If no session exists (or if session is invalid?)
|
||||
# it's gonna return the default empty dict,
|
||||
# which we interpret as an authentication failure
|
||||
infos = request.get_cookie(
|
||||
"yunohost.admin", secret=session_secret, default={}
|
||||
)
|
||||
except Exception:
|
||||
if not raise_if_no_session_exists:
|
||||
return {"id": random_ascii()}
|
||||
raise YunohostAuthenticationError("unable_authenticate")
|
||||
|
||||
if "id" not in infos:
|
||||
infos["id"] = random_ascii()
|
||||
|
||||
# FIXME: Here, maybe we want to re-authenticate the session via the authenticator
|
||||
# For example to check that the username authenticated is still in the admin group...
|
||||
|
||||
return infos
|
||||
|
||||
@staticmethod
|
||||
def delete_session_cookie(self):
|
||||
|
||||
from bottle import response
|
||||
|
||||
response.set_cookie("yunohost.admin", "", max_age=-1)
|
||||
response.delete_cookie("yunohost.admin")
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
"""
|
||||
|
||||
from moulinette.core import MoulinetteError
|
||||
from moulinette.core import MoulinetteError, MoulinetteAuthenticationError
|
||||
from moulinette import m18n
|
||||
|
||||
|
||||
|
@ -60,3 +60,9 @@ class YunohostValidationError(YunohostError):
|
|||
def content(self):
|
||||
|
||||
return {"error": self.strerror, "error_key": self.key, **self.kwargs}
|
||||
|
||||
|
||||
class YunohostAuthenticationError(MoulinetteAuthenticationError):
|
||||
|
||||
pass
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue