OpenSlides/server/openslides/utils/middleware.py
FinnStutzenstein 2bcab5d098
Repository restructure
- moved all server related things into the folder `server`, so this
configuration is parallel to the client.
- All main "services" are now folders in the root directory
- Added Dockerfiles to each service (currently server and client)
- Added a docker compose configuration to start everything together.
Currently there are heavy dependencies into https://github.com/OpenSlides/openslides-docker-compose
- Resturctured the .gitignore. If someone needs something excluded,
please add it to the right section.
- Added initial build setup with Docker and docker-compose.
- removed setup.py. We won't deliver OpenSlides via pip anymore.
2020-08-21 08:11:13 +02:00

74 lines
2.4 KiB
Python

from typing import Any, Dict, Optional
from channels.auth import (
AuthMiddleware,
CookieMiddleware,
SessionMiddleware,
_get_user_session_key,
)
from django.conf import settings
from django.contrib.auth import BACKEND_SESSION_KEY, HASH_SESSION_KEY
from django.utils.crypto import constant_time_compare
from .cache import element_cache
class CollectionAuthMiddleware(AuthMiddleware):
"""
Like the channels AuthMiddleware but returns a user dict id instead of
a django Model as user.
"""
def populate_scope(self, scope: Dict[str, Any]) -> None:
# Make sure we have a session
if "session" not in scope:
raise ValueError(
"AuthMiddleware cannot find session in scope. SessionMiddleware must be above it."
)
# Add it to the scope if it's not there already
if "user" not in scope:
scope["user"] = {}
async def resolve_scope(self, scope: Dict[str, Any]) -> None:
scope["user"].update(await get_user(scope))
async def get_user(scope: Dict[str, Any]) -> Dict[str, Any]:
"""
Returns a user id from a channels-scope-session.
If no user is retrieved, return {'id': 0}.
"""
# This code is basicly from channels.auth:
# https://github.com/django/channels/blob/d5e81a78e96770127da79248349808b6ee6ec2a7/channels/auth.py#L16
if "session" not in scope:
raise ValueError(
"Cannot find session in scope. You should wrap your consumer in SessionMiddleware."
)
session = scope["session"]
user: Optional[Dict[str, Any]] = None
try:
user_id = _get_user_session_key(session)
backend_path = session[BACKEND_SESSION_KEY]
except KeyError:
pass
else:
if backend_path in settings.AUTHENTICATION_BACKENDS:
user = await element_cache.get_element_data("users/user", user_id)
if user:
# Verify the session
session_hash = session.get(HASH_SESSION_KEY)
session_hash_verified = session_hash and constant_time_compare(
session_hash, user["session_auth_hash"]
)
if not session_hash_verified:
session.flush()
user = None
return user or {"id": 0}
# Handy shortcut for applying all three layers at once
AuthMiddlewareStack = lambda inner: CookieMiddleware( # noqa
SessionMiddleware(CollectionAuthMiddleware(inner))
)