Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

165 Validate role service partially also in wait_for_deps.py #995

Merged
merged 4 commits into from
Jan 5, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions src/layman/__init__.py
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@
from redis import WatchError

import layman_settings as settings
from layman_start_util import validate_role_service

IN_CELERY_WORKER_PROCESS = sys.argv and sys.argv[0].endswith('/celery/__main__.py')
IN_PYTEST_PROCESS = sys.argv and sys.argv[0].endswith('/pytest/__main__.py')
@@ -129,8 +130,9 @@
set_after_restart()

logger.info(f'Validate Role service data')
from .authz.role_service import validate_role_service
validate_role_service()
from .common.prime_db_schema.users import get_user_infos
usernames = get_user_infos().keys()
validate_role_service(layman_usernames=usernames)

pipe.multi()
pipe.set(LAYMAN_DEPS_ADJUSTED_KEY, 'done')
84 changes: 4 additions & 80 deletions src/layman/authz/role_service.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,10 @@
import logging

from db import util as db_util
from geoserver import util as gs_util
from layman import settings

logger = logging.getLogger(__name__)

ROLE_NAME_PATTERN = r'^(?!.{65,})[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$'


def get_user_roles(username):
query = f"""
@@ -17,7 +14,9 @@ def get_user_roles(username):
and LEFT(rolename, 5) != 'USER_'
and rolename ~ %s
"""
roles = db_util.run_query(query, (username, 'ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE, ROLE_NAME_PATTERN), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
roles = db_util.run_query(query,
(username, 'ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE, settings.ROLE_NAME_PATTERN),
uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
return {role[0] for role in roles}


@@ -37,80 +36,5 @@ def get_all_roles():
and LEFT(name, 5) != 'USER_'
and name ~ %s
"""
roles = db_util.run_query(query, ('ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE, ROLE_NAME_PATTERN), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
roles = db_util.run_query(query, ('ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE, settings.ROLE_NAME_PATTERN), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
return [role[0] for role in roles] + [settings.RIGHTS_EVERYONE_ROLE]


def validate_role_table():
expected_roles = ['ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE]
query = f"""
select unnest(%s)
EXCEPT
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
"""
roles = db_util.run_query(query, (expected_roles,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Missing roles in JDBC Role service: {[role[0] for role in roles]}")

query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where name !~ %s
"""
roles = db_util.run_query(query, (ROLE_NAME_PATTERN,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles not matching pattern '{ROLE_NAME_PATTERN}' in JDBC Role service: {[role[0] for role in roles]}")

not_expected_roles = [settings.RIGHTS_EVERYONE_ROLE, ] + gs_util.RESERVED_ROLE_NAMES
query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where name = any(%s)
"""
roles = db_util.run_query(query, (not_expected_roles,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles {not_expected_roles} should not be in JDBC Role service.")

query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where parent is not null
"""
roles = db_util.run_query(query, uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles in JDBC Role service should not have parent column filled: {[role[0] for role in roles]}.")


def validate_user_roles_table():
exp_relation = [(settings.LAYMAN_GS_USER, 'ADMIN'),
(settings.LAYMAN_GS_USER, settings.LAYMAN_GS_ROLE),
(settings.GEOSERVER_ADMIN_USER, 'ADMIN'),
]
query = f"""
with exp_relations as(
SELECT w.name, %s
FROM {settings.LAYMAN_PRIME_SCHEMA}.users u inner join
{settings.LAYMAN_PRIME_SCHEMA}.workspaces w on u.id_workspace = w.id
UNION ALL
select w.name as username,
concat('USER_', UPPER(w.name)) as rolename
from {settings.LAYMAN_PRIME_SCHEMA}.users u inner join
{settings.LAYMAN_PRIME_SCHEMA}.workspaces w on w.id = u.id_workspace
UNION ALL
select * from unnest (%s, %s) as exp_user_role(username, rolename)
)
select * from exp_relations
except
select username, rolename
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.user_roles
"""
user_roles = db_util.run_query(query, (settings.LAYMAN_GS_ROLE, [rel[0] for rel in exp_relation], [rel[1] for rel in exp_relation]), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if user_roles:
raise Exception(
f"Missing user-role relation in JDBC Role service table user_roles: {[{'username': user_role[0], 'rolename': user_role[1]} for user_role in user_roles]}")


def validate_role_service():
validate_role_table()
validate_user_roles_table()
4 changes: 2 additions & 2 deletions src/layman/common/prime_db_schema/publications.py
Original file line number Diff line number Diff line change
@@ -364,9 +364,9 @@ def only_valid_role_names(roles_list):
if not roles_list:
return

not_matching_roles = [r for r in roles_list if not re.match(role_service.ROLE_NAME_PATTERN, r)]
not_matching_roles = [r for r in roles_list if not re.match(settings.ROLE_NAME_PATTERN, r)]
if not_matching_roles:
raise LaymanError(43, f'Found roles not matching to regex {role_service.ROLE_NAME_PATTERN} '
raise LaymanError(43, f'Found roles not matching to regex {settings.ROLE_NAME_PATTERN} '
f': {not_matching_roles}')

internal_user_roles = [r for r in roles_list if r.startswith('USER_')]
2 changes: 2 additions & 0 deletions src/layman_settings.py
Original file line number Diff line number Diff line change
@@ -277,3 +277,5 @@ class EnumWfsWmsStatus(Enum):

OGR_DEFAULT_PRIMARY_KEY = 'ogc_fid'
OGR_DEFAULT_GEOMETRY_COLUMN = 'wkb_geometry'

ROLE_NAME_PATTERN = r'^(?!.{65,})[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$'
69 changes: 69 additions & 0 deletions src/layman_start_util.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import layman_settings as settings
from db import util as db_util
from geoserver import util as gs_util


def validate_role_table():
expected_roles = ['ADMIN', 'GROUP_ADMIN', settings.LAYMAN_GS_ROLE]
query = f"""
select unnest(%s)
EXCEPT
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
"""
roles = db_util.run_query(query, (expected_roles,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Missing roles in JDBC Role service: {[role[0] for role in roles]}")

query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where name !~ %s
"""
roles = db_util.run_query(query, (settings.ROLE_NAME_PATTERN,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles not matching pattern '{settings.ROLE_NAME_PATTERN}' in JDBC Role service: {[role[0] for role in roles]}")

not_expected_roles = [settings.RIGHTS_EVERYONE_ROLE, ] + gs_util.RESERVED_ROLE_NAMES
query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where name = any(%s)
"""
roles = db_util.run_query(query, (not_expected_roles,), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles {not_expected_roles} should not be in JDBC Role service.")

query = f"""
select name
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.roles
where parent is not null
"""
roles = db_util.run_query(query, uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if roles:
raise Exception(f"Roles in JDBC Role service should not have parent column filled: {[role[0] for role in roles]}.")


def validate_user_roles_table(*, layman_usernames):
exp_relation = [(settings.LAYMAN_GS_USER, 'ADMIN'),
(settings.LAYMAN_GS_USER, settings.LAYMAN_GS_ROLE),
(settings.GEOSERVER_ADMIN_USER, 'ADMIN'),
] + [(username, f"USER_{username.upper()}") for username in layman_usernames]
query = f"""
with exp_relations as(
select * from unnest (%s, %s) as exp_user_role(username, rolename)
)
select * from exp_relations
except
select username, rolename
from {settings.LAYMAN_ROLE_SERVICE_SCHEMA}.user_roles
"""
user_roles = db_util.run_query(query, ([rel[0] for rel in exp_relation], [rel[1] for rel in exp_relation]), uri_str=settings.LAYMAN_ROLE_SERVICE_URI)
if user_roles:
raise Exception(
f"Missing user-role relation in JDBC Role service table user_roles: {[{'username': user_role[0], 'rolename': user_role[1]} for user_role in user_roles]}")


def validate_role_service(*, layman_usernames):
validate_role_table()
validate_user_roles_table(layman_usernames=layman_usernames)
4 changes: 3 additions & 1 deletion src/wait_for_deps.py
Original file line number Diff line number Diff line change
@@ -4,8 +4,9 @@
from urllib.parse import urljoin

import geoserver
import layman_settings as settings
from geoserver.role_service import check_jdbc_role_service
import layman_settings as settings
from layman_start_util import validate_role_service

ATTEMPT_INTERVAL = 2
MAX_ATTEMPTS = 60
@@ -51,6 +52,7 @@ def main():
# Check PostgreSQL role service and stops immediately in case of any error
print(f"Checking PostgreSQL role service")
check_jdbc_role_service(settings.LAYMAN_ROLE_SERVICE_URI, settings.LAYMAN_ROLE_SERVICE_SCHEMA)
validate_role_service(layman_usernames=[])
print()

# QGIS Server