group: extend username check

This commit is contained in:
Peter Bieringer
2026-07-18 15:05:25 +02:00
parent 4303f2a938
commit ffb95dc4ea

View File

@@ -22,9 +22,10 @@ import sys
import unicodedata import unicodedata
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from typing import Optional, Union from typing import Optional, Union
from urllib.parse import unquote
from radicale import (auth, config, hook, httputils, log, pathutils, rights, from radicale import (auth, config, group, hook, httputils, log, pathutils,
sharing, storage, types, utils, web, xmlutils) rights, sharing, storage, types, utils, web, xmlutils)
from radicale.log import logger from radicale.log import logger
from radicale.rights import intersect from radicale.rights import intersect
@@ -84,8 +85,30 @@ def _check_format(self: storage.BaseStorage,
def _check_user_format(self: storage.BaseStorage, def _check_user_format(self: storage.BaseStorage,
user: str, user: str,
validation_type: str validation_type: str,
urldecode_username: bool,
enforceUser: bool = True,
) -> bool: ) -> bool:
logger.trace("_check_user_format investigate %r (urldecode_username=%r)", user, urldecode_username)
if urldecode_username:
user = unquote(user)
if (user.startswith(sharing.SHARING_SEPARATOR_GROUP) or user.startswith(sharing.SHARING_SEPARATOR_REALM)):
if enforceUser:
# group/realm identifiers
return False
else:
# strip 1st char
user = user[1:]
if enforceUser:
if user.count(sharing.SHARING_SEPARATOR_GROUP) > 0:
# not allowed (avoid injecting a group)
return False
elif user.count(sharing.SHARING_SEPARATOR_REALM) > 1:
# only allowed once
return False
if (user.endswith(sharing.SHARING_SEPARATOR_GROUP) or user.endswith(sharing.SHARING_SEPARATOR_REALM)):
# group/realm identifiers
return False
if validation_type == "strict": if validation_type == "strict":
return (re.search(USER_PATTERN_STRICT_RE, user) is not None) return (re.search(USER_PATTERN_STRICT_RE, user) is not None)
else: else:
@@ -116,6 +139,7 @@ class ApplicationBase:
configuration: config.Configuration configuration: config.Configuration
_auth: auth.BaseAuth _auth: auth.BaseAuth
_group: group.BaseGroup
_storage: storage.BaseStorage _storage: storage.BaseStorage
_rights: rights.BaseRights _rights: rights.BaseRights
_web: web.BaseWeb _web: web.BaseWeb
@@ -133,6 +157,7 @@ class ApplicationBase:
def __init__(self, configuration: config.Configuration) -> None: def __init__(self, configuration: config.Configuration) -> None:
self.configuration = configuration self.configuration = configuration
self._auth = auth.load(configuration) self._auth = auth.load(configuration)
self._group = group.load(configuration)
self._storage = storage.load(configuration) self._storage = storage.load(configuration)
self._rights = rights.load(configuration) self._rights = rights.load(configuration)
self._web = web.load(configuration) self._web = web.load(configuration)