allow read only pages to be requested without authorization

This commit is contained in:
Evgenii Alekseev 2021-09-05 06:09:43 +03:00
parent e0607ba609
commit b0575ee4ba
7 changed files with 27 additions and 11 deletions

View File

@ -23,6 +23,7 @@ libalpm and AUR related configuration.
Base authorization settings.
* `target` - specifies authorization provider, string, optional, default `disabled`. Allowed values are `disabled`, `configuration`.
* `allow_read_only` - allow to request read only pages without authorization, boolean, required.
* `allowed_paths` - URI paths (exact match) which can be accessed without authorization, space separated list of strings, optional.
* `allowed_paths_groups` - URI paths prefixes which can be accessed without authorization, space separated list of strings, optional.
* `salt` - password hash salt, string, required in case if authorization enabled (automatically generated by `create-user` subcommand).

View File

@ -10,6 +10,7 @@ root = /
[auth]
target = disabled
allow_read_only = yes
[build]
archbuild_flags =

View File

@ -45,6 +45,7 @@ class Auth:
:param configuration: configuration instance
:param provider: authorization type definition
"""
self.allow_read_only = configuration.getboolean("auth", "allow_read_only")
self.allowed_paths = set(configuration.getlist("auth", "allowed_paths"))
self.allowed_paths.update(self.ALLOWED_PATHS)
self.allowed_paths_groups = set(configuration.getlist("auth", "allowed_paths_groups"))
@ -74,14 +75,17 @@ class Auth:
del username, password
return True
def is_safe_request(self, uri: Optional[str]) -> bool:
def is_safe_request(self, uri: Optional[str], required: UserAccess) -> bool:
"""
check if requested path are allowed without authorization
:param uri: request uri
:param required: required access level
:return: True in case if this URI can be requested without authorization and False otherwise
"""
if not uri:
return False # request without context is not allowed
if required == UserAccess.Read and self.allow_read_only:
return True # in case if read right requested and allowed in options
return uri in self.allowed_paths or any(uri.startswith(path) for path in self.allowed_paths_groups)
def known_username(self, username: str) -> bool: # pylint: disable=no-self-use

View File

@ -80,7 +80,7 @@ def auth_handler(validator: Auth) -> MiddlewareType:
else:
permission = UserAccess.Write
if not validator.is_safe_request(request.path):
if not validator.is_safe_request(request.path, permission):
await aiohttp_security.check_permission(request, permission, request.path)
return await handler(request)

View File

@ -85,7 +85,7 @@ class IndexView(BaseView):
# auth block
auth_username = await authorized_userid(self.request)
authorized = not self.validator.enabled or auth_username is not None
authorized = not self.validator.enabled or self.validator.allow_read_only or auth_username is not None
return {
"architecture": self.service.architecture,

View File

@ -46,24 +46,33 @@ def test_is_safe_request(auth: Auth) -> None:
must validate safe request
"""
# login and logout are always safe
assert auth.is_safe_request("/login")
assert auth.is_safe_request("/logout")
assert auth.is_safe_request("/login", UserAccess.Write)
assert auth.is_safe_request("/logout", UserAccess.Write)
auth.allowed_paths.add("/safe")
auth.allowed_paths_groups.add("/unsafe/safe")
assert auth.is_safe_request("/safe")
assert not auth.is_safe_request("/unsafe")
assert auth.is_safe_request("/unsafe/safe")
assert auth.is_safe_request("/unsafe/safe/suffix")
assert auth.is_safe_request("/safe", UserAccess.Write)
assert not auth.is_safe_request("/unsafe", UserAccess.Write)
assert auth.is_safe_request("/unsafe/safe", UserAccess.Write)
assert auth.is_safe_request("/unsafe/safe/suffix", UserAccess.Write)
def test_is_safe_request_empty(auth: Auth) -> None:
"""
must not allow requests without path
"""
assert not auth.is_safe_request(None)
assert not auth.is_safe_request("")
assert not auth.is_safe_request(None, UserAccess.Read)
assert not auth.is_safe_request("", UserAccess.Read)
def test_is_safe_request_read_only(auth: Auth) -> None:
"""
must allow read-only requests if it is set in settings
"""
assert auth.is_safe_request("/", UserAccess.Read)
auth.allow_read_only = True
assert auth.is_safe_request("/unsafe", UserAccess.Read)
def test_known_username(auth: Auth, user: User) -> None:

View File

@ -9,6 +9,7 @@ repositories = core extra community multilib
root = /
[auth]
allow_read_only = no
salt = salt
[build]