mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 07:17:17 +00:00
allow read only pages to be requested without authorization
This commit is contained in:
parent
d7bf647493
commit
19d1e17727
@ -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).
|
||||
|
@ -10,6 +10,7 @@ root = /
|
||||
|
||||
[auth]
|
||||
target = disabled
|
||||
allow_read_only = yes
|
||||
|
||||
[build]
|
||||
archbuild_flags =
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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:
|
||||
|
@ -9,6 +9,7 @@ repositories = core extra community multilib
|
||||
root = /
|
||||
|
||||
[auth]
|
||||
allow_read_only = no
|
||||
salt = salt
|
||||
|
||||
[build]
|
||||
|
Loading…
Reference in New Issue
Block a user