mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-04-24 23:37:18 +00:00
allow read only pages to be requested without authorization
This commit is contained in:
parent
e0607ba609
commit
b0575ee4ba
@ -23,6 +23,7 @@ libalpm and AUR related configuration.
|
|||||||
Base authorization settings.
|
Base authorization settings.
|
||||||
|
|
||||||
* `target` - specifies authorization provider, string, optional, default `disabled`. Allowed values are `disabled`, `configuration`.
|
* `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` - 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.
|
* `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).
|
* `salt` - password hash salt, string, required in case if authorization enabled (automatically generated by `create-user` subcommand).
|
||||||
|
@ -10,6 +10,7 @@ root = /
|
|||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
target = disabled
|
target = disabled
|
||||||
|
allow_read_only = yes
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
archbuild_flags =
|
archbuild_flags =
|
||||||
|
@ -45,6 +45,7 @@ class Auth:
|
|||||||
:param configuration: configuration instance
|
:param configuration: configuration instance
|
||||||
:param provider: authorization type definition
|
: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 = set(configuration.getlist("auth", "allowed_paths"))
|
||||||
self.allowed_paths.update(self.ALLOWED_PATHS)
|
self.allowed_paths.update(self.ALLOWED_PATHS)
|
||||||
self.allowed_paths_groups = set(configuration.getlist("auth", "allowed_paths_groups"))
|
self.allowed_paths_groups = set(configuration.getlist("auth", "allowed_paths_groups"))
|
||||||
@ -74,14 +75,17 @@ class Auth:
|
|||||||
del username, password
|
del username, password
|
||||||
return True
|
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
|
check if requested path are allowed without authorization
|
||||||
:param uri: request uri
|
:param uri: request uri
|
||||||
|
:param required: required access level
|
||||||
:return: True in case if this URI can be requested without authorization and False otherwise
|
:return: True in case if this URI can be requested without authorization and False otherwise
|
||||||
"""
|
"""
|
||||||
if not uri:
|
if not uri:
|
||||||
return False # request without context is not allowed
|
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)
|
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
|
def known_username(self, username: str) -> bool: # pylint: disable=no-self-use
|
||||||
|
@ -80,7 +80,7 @@ def auth_handler(validator: Auth) -> MiddlewareType:
|
|||||||
else:
|
else:
|
||||||
permission = UserAccess.Write
|
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)
|
await aiohttp_security.check_permission(request, permission, request.path)
|
||||||
|
|
||||||
return await handler(request)
|
return await handler(request)
|
||||||
|
@ -85,7 +85,7 @@ class IndexView(BaseView):
|
|||||||
|
|
||||||
# auth block
|
# auth block
|
||||||
auth_username = await authorized_userid(self.request)
|
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 {
|
return {
|
||||||
"architecture": self.service.architecture,
|
"architecture": self.service.architecture,
|
||||||
|
@ -46,24 +46,33 @@ def test_is_safe_request(auth: Auth) -> None:
|
|||||||
must validate safe request
|
must validate safe request
|
||||||
"""
|
"""
|
||||||
# login and logout are always safe
|
# login and logout are always safe
|
||||||
assert auth.is_safe_request("/login")
|
assert auth.is_safe_request("/login", UserAccess.Write)
|
||||||
assert auth.is_safe_request("/logout")
|
assert auth.is_safe_request("/logout", UserAccess.Write)
|
||||||
|
|
||||||
auth.allowed_paths.add("/safe")
|
auth.allowed_paths.add("/safe")
|
||||||
auth.allowed_paths_groups.add("/unsafe/safe")
|
auth.allowed_paths_groups.add("/unsafe/safe")
|
||||||
|
|
||||||
assert auth.is_safe_request("/safe")
|
assert auth.is_safe_request("/safe", UserAccess.Write)
|
||||||
assert not auth.is_safe_request("/unsafe")
|
assert not auth.is_safe_request("/unsafe", UserAccess.Write)
|
||||||
assert auth.is_safe_request("/unsafe/safe")
|
assert auth.is_safe_request("/unsafe/safe", UserAccess.Write)
|
||||||
assert auth.is_safe_request("/unsafe/safe/suffix")
|
assert auth.is_safe_request("/unsafe/safe/suffix", UserAccess.Write)
|
||||||
|
|
||||||
|
|
||||||
def test_is_safe_request_empty(auth: Auth) -> None:
|
def test_is_safe_request_empty(auth: Auth) -> None:
|
||||||
"""
|
"""
|
||||||
must not allow requests without path
|
must not allow requests without path
|
||||||
"""
|
"""
|
||||||
assert not auth.is_safe_request(None)
|
assert not auth.is_safe_request(None, UserAccess.Read)
|
||||||
assert not auth.is_safe_request("")
|
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:
|
def test_known_username(auth: Auth, user: User) -> None:
|
||||||
|
@ -9,6 +9,7 @@ repositories = core extra community multilib
|
|||||||
root = /
|
root = /
|
||||||
|
|
||||||
[auth]
|
[auth]
|
||||||
|
allow_read_only = no
|
||||||
salt = salt
|
salt = salt
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
|
Loading…
Reference in New Issue
Block a user