mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
app/permissions: Move permissions data out of LDAP
This commit is contained in:
parent
54fd311bec
commit
c5580a0551
5 changed files with 153 additions and 91 deletions
|
@ -68,28 +68,16 @@ groupPermission: cn=all_users,ou=groups,dc=yunohost,dc=org
|
|||
cn: mail.main
|
||||
objectClass: posixGroup
|
||||
objectClass: permissionYnh
|
||||
isProtected: TRUE
|
||||
label: E-mail
|
||||
gidNumber: 5001
|
||||
showTile: FALSE
|
||||
authHeader: FALSE
|
||||
|
||||
dn: cn=ssh.main,ou=permission,dc=yunohost,dc=org
|
||||
cn: ssh.main
|
||||
objectClass: posixGroup
|
||||
objectClass: permissionYnh
|
||||
isProtected: TRUE
|
||||
label: SSH
|
||||
gidNumber: 5003
|
||||
showTile: FALSE
|
||||
authHeader: FALSE
|
||||
|
||||
dn: cn=sftp.main,ou=permission,dc=yunohost,dc=org
|
||||
cn: sftp.main
|
||||
objectClass: posixGroup
|
||||
objectClass: permissionYnh
|
||||
isProtected: TRUE
|
||||
label: SFTP
|
||||
gidNumber: 5004
|
||||
showTile: FALSE
|
||||
authHeader: FALSE
|
||||
|
|
|
@ -14,24 +14,6 @@ olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.2 NAME 'groupPermission'
|
|||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.3 NAME 'inheritPermission'
|
||||
DESC 'YunoHost permission for user on permission side'
|
||||
SUP distinguishedName )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.4 NAME 'URL'
|
||||
DESC 'YunoHost permission main URL'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.5 NAME 'additionalUrls'
|
||||
DESC 'YunoHost permission additionnal URL'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.6 NAME 'authHeader'
|
||||
DESC 'YunoHost application, enable authentication header'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.7 NAME 'label'
|
||||
DESC 'YunoHost permission label, also used for the tile name in the SSO'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.8 NAME 'showTile'
|
||||
DESC 'YunoHost application, show/hide the tile in the SSO for this permission'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.9 NAME 'isProtected'
|
||||
DESC 'YunoHost application permission protection'
|
||||
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
|
||||
# OBJECTCLASS
|
||||
# For Applications
|
||||
olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.1 NAME 'groupOfNamesYnh'
|
||||
|
@ -41,8 +23,8 @@ olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.1 NAME 'groupOfNamesYnh'
|
|||
olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.2 NAME 'permissionYnh'
|
||||
DESC 'a YunoHost application'
|
||||
SUP top AUXILIARY
|
||||
MUST ( cn $ authHeader $ label $ showTile $ isProtected )
|
||||
MAY ( groupPermission $ inheritPermission $ URL $ additionalUrls ) )
|
||||
MUST ( cn )
|
||||
MAY ( groupPermission $ inheritPermission ) )
|
||||
# For User
|
||||
olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.3 NAME 'userPermissionYnh'
|
||||
DESC 'a YunoHost application'
|
||||
|
|
74
src/migrations/0031_rework_permission_infos.py
Normal file
74
src/migrations/0031_rework_permission_infos.py
Normal file
|
@ -0,0 +1,74 @@
|
|||
from logging import getLogger
|
||||
|
||||
from yunohost.tools import Migration
|
||||
from yunohost.permission import permission_sync_to_user
|
||||
from yunohost.app import app_setting
|
||||
|
||||
logger = getLogger("yunohost.migration")
|
||||
|
||||
###################################################
|
||||
# Tools used also for restoration
|
||||
###################################################
|
||||
|
||||
|
||||
class MyMigration(Migration):
|
||||
|
||||
introduced_in_version = "12.0" # FIXME ?
|
||||
dependencies = []
|
||||
|
||||
ldap_migration_started = False
|
||||
|
||||
@Migration.ldap_migration
|
||||
def run(self, *args):
|
||||
|
||||
self.ldap_migration_started = True
|
||||
|
||||
permissions_per_app = self.read_legacy_permissions_per_app()
|
||||
for app, permissions in permissions_per_app.items():
|
||||
app_setting(app, "_permissions", permissions)
|
||||
|
||||
permission_sync_to_user()
|
||||
|
||||
def run_after_system_restore(self):
|
||||
self.run()
|
||||
|
||||
def read_legacy_permissions_per_app(self):
|
||||
|
||||
from yunohost.utils.ldap import _get_ldap_interface
|
||||
SYSTEM_PERMS = ["mail", "sftp", "ssh"]
|
||||
|
||||
ldap = _get_ldap_interface()
|
||||
permissions_infos = ldap.search(
|
||||
"ou=permission",
|
||||
"(objectclass=permissionYnh)",
|
||||
[
|
||||
"cn",
|
||||
"URL",
|
||||
"additionalUrls",
|
||||
"authHeader",
|
||||
"label",
|
||||
"showTile",
|
||||
"isProtected",
|
||||
],
|
||||
)
|
||||
|
||||
permissions_per_app = {}
|
||||
for infos in permissions_infos:
|
||||
app, name = infos["cn"][0].split(".")
|
||||
|
||||
if app in SYSTEM_PERMS:
|
||||
continue
|
||||
|
||||
if app not in permissions_per_app:
|
||||
permissions_per_app[app] = {}
|
||||
|
||||
permissions_per_app[app][name] = {
|
||||
"label": infos.get("label", [None])[0],
|
||||
"show_tile": infos.get("showTile", [False])[0] == "TRUE",
|
||||
"auth_header": infos.get("authHeader", [False])[0] == "TRUE",
|
||||
"protected": infos.get("isProtected", [False])[0] == "TRUE",
|
||||
"url": infos.get("URL", [None])[0],
|
||||
"additional_urls": infos.get("additionalUrls", []),
|
||||
}
|
||||
|
||||
return permissions_per_app
|
|
@ -49,19 +49,13 @@ def user_permission_list(
|
|||
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
|
||||
|
||||
ldap = _get_ldap_interface()
|
||||
permissions_infos = ldap.search(
|
||||
ldap_permissions_infos = ldap.search(
|
||||
"ou=permission",
|
||||
"(objectclass=permissionYnh)",
|
||||
[
|
||||
"cn",
|
||||
"groupPermission",
|
||||
"inheritPermission",
|
||||
"URL",
|
||||
"additionalUrls",
|
||||
"authHeader",
|
||||
"label",
|
||||
"showTile",
|
||||
"isProtected",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -78,9 +72,9 @@ def user_permission_list(
|
|||
}
|
||||
|
||||
permissions = {}
|
||||
for infos in permissions_infos:
|
||||
for infos in ldap_permissions_infos:
|
||||
name = infos["cn"][0]
|
||||
app = name.split(".")[0]
|
||||
app, subperm = name.split(".")
|
||||
|
||||
if ignore_system_perms and app in SYSTEM_PERMS:
|
||||
continue
|
||||
|
@ -88,20 +82,19 @@ def user_permission_list(
|
|||
continue
|
||||
|
||||
perm = {}
|
||||
perm["allowed"] = [
|
||||
_ldap_path_extract(p, "cn") for p in infos.get("groupPermission", [])
|
||||
]
|
||||
|
||||
if full:
|
||||
perm["corresponding_users"] = [
|
||||
_ldap_path_extract(p, "uid") for p in infos.get("inheritPermission", [])
|
||||
]
|
||||
perm["auth_header"] = infos.get("authHeader", [False])[0] == "TRUE"
|
||||
perm["label"] = infos.get("label", [None])[0]
|
||||
perm["show_tile"] = infos.get("showTile", [False])[0] == "TRUE"
|
||||
perm["protected"] = infos.get("isProtected", [False])[0] == "TRUE"
|
||||
perm["url"] = infos.get("URL", [None])[0]
|
||||
perm["additional_urls"] = infos.get("additionalUrls", [])
|
||||
if full and app not in SYSTEM_PERMS:
|
||||
# Default stuff
|
||||
perm = {
|
||||
"url": None,
|
||||
"additional_urls": [],
|
||||
"auth_header": True,
|
||||
"show_tile": None, # To be automagically set to True by default if an url is defined and show_tile not provided
|
||||
"protected": False,
|
||||
}
|
||||
perm_settings = (app_setting(app, "_permissions") or {}).get(subperm, {})
|
||||
perm.update(perm_settings)
|
||||
if perm["show_tile"] is None and perm["url"] is not None:
|
||||
perm["show_tile"] = True
|
||||
|
||||
if absolute_urls:
|
||||
app_base_path = (
|
||||
|
@ -113,6 +106,14 @@ def user_permission_list(
|
|||
for url in perm["additional_urls"]
|
||||
]
|
||||
|
||||
perm["allowed"] = [
|
||||
_ldap_path_extract(p, "cn") for p in infos.get("groupPermission", [])
|
||||
]
|
||||
if full:
|
||||
perm["corresponding_users"] = [
|
||||
_ldap_path_extract(p, "uid") for p in infos.get("inheritPermission", [])
|
||||
]
|
||||
|
||||
permissions[name] = perm
|
||||
|
||||
# Make sure labels for sub-permissions are the form " Applabel (Sublabel) "
|
||||
|
@ -414,16 +415,6 @@ def permission_create(
|
|||
"objectClass": ["top", "permissionYnh", "posixGroup"],
|
||||
"cn": str(permission),
|
||||
"gidNumber": gid,
|
||||
"authHeader": ["TRUE"],
|
||||
"label": [
|
||||
str(label) if label else (subperm if subperm != "main" else app.title())
|
||||
],
|
||||
"showTile": [
|
||||
"FALSE"
|
||||
], # Dummy value, it will be fixed when we call '_update_ldap_group_permission'
|
||||
"isProtected": [
|
||||
"FALSE"
|
||||
], # Dummy value, it will be fixed when we call '_update_ldap_group_permission'
|
||||
}
|
||||
|
||||
if allowed is not None:
|
||||
|
@ -446,6 +437,8 @@ def permission_create(
|
|||
"permission_creation_failed", permission=permission, error=e
|
||||
)
|
||||
|
||||
label = str(label) if label else (subperm if subperm != "main" else app.title())
|
||||
|
||||
try:
|
||||
permission_url(
|
||||
permission,
|
||||
|
@ -463,6 +456,7 @@ def permission_create(
|
|||
protected=protected,
|
||||
sync_perm=sync_perm,
|
||||
)
|
||||
|
||||
except Exception:
|
||||
permission_delete(permission, force=True)
|
||||
raise
|
||||
|
@ -496,15 +490,15 @@ def permission_url(
|
|||
clear_urls -- (optional) Clean all urls (url and additional_urls)
|
||||
"""
|
||||
from yunohost.app import app_setting
|
||||
from yunohost.utils.ldap import _get_ldap_interface
|
||||
|
||||
ldap = _get_ldap_interface()
|
||||
|
||||
# By default, manipulate main permission
|
||||
if "." not in permission:
|
||||
permission = permission + ".main"
|
||||
|
||||
app = permission.split(".")[0]
|
||||
app, sub_permission = permission.split(".")
|
||||
|
||||
if app in SYSTEM_PERMS:
|
||||
logger.warning(f"Cannot change urls / auth_header for system perm {permission}")
|
||||
|
||||
if url or add_url:
|
||||
domain = app_setting(app, "domain")
|
||||
|
@ -573,19 +567,20 @@ def permission_url(
|
|||
|
||||
# Actually commit the change
|
||||
|
||||
operation_logger.related_to.append(("app", permission.split(".")[0]))
|
||||
operation_logger.related_to.append(("app", app))
|
||||
operation_logger.start()
|
||||
|
||||
try:
|
||||
ldap.update(
|
||||
f"cn={permission},ou=permission",
|
||||
{
|
||||
"URL": [url] if url is not None else [],
|
||||
"additionalUrls": new_additional_urls,
|
||||
"authHeader": [str(auth_header).upper()],
|
||||
"showTile": [str(show_tile).upper()],
|
||||
},
|
||||
)
|
||||
perm_settings = app_setting(app, "_permissions") or {}
|
||||
if sub_permission not in perm_settings:
|
||||
perm_settings[sub_permission] = {}
|
||||
perm_settings[sub_permission].update({
|
||||
"url": url,
|
||||
"additional_urls": new_additional_urls,
|
||||
"auth_header": auth_header,
|
||||
"show_tile": show_tile,
|
||||
})
|
||||
app_setting(app, "_permissions", perm_settings)
|
||||
except Exception as e:
|
||||
raise YunohostError("permission_update_failed", permission=permission, error=e)
|
||||
|
||||
|
@ -714,31 +709,42 @@ def _update_ldap_group_permission(
|
|||
- the 'allowed' list contains *existing* groups.
|
||||
"""
|
||||
|
||||
from yunohost.app import app_setting
|
||||
from yunohost.hook import hook_callback
|
||||
from yunohost.utils.ldap import _get_ldap_interface
|
||||
|
||||
ldap = _get_ldap_interface()
|
||||
|
||||
app, sub_permission = permission.split(".")
|
||||
existing_permission = user_permission_info(permission)
|
||||
|
||||
update = {}
|
||||
update_ldap = {}
|
||||
update_settings = {}
|
||||
|
||||
if allowed is not None:
|
||||
allowed = [allowed] if not isinstance(allowed, list) else allowed
|
||||
# Guarantee uniqueness of values in allowed, which would otherwise make ldap.update angry.
|
||||
allowed = set(allowed)
|
||||
update["groupPermission"] = [
|
||||
update_ldap["groupPermission"] = [
|
||||
"cn=" + g + ",ou=groups,dc=yunohost,dc=org" for g in allowed
|
||||
]
|
||||
|
||||
if label is not None:
|
||||
update["label"] = [str(label)]
|
||||
if app in SYSTEM_PERMS:
|
||||
logger.warning(f"Can't change 'label' for system permission {permission}")
|
||||
else:
|
||||
update_settings["label"] = str(label)
|
||||
|
||||
if protected is not None:
|
||||
update["isProtected"] = [str(protected).upper()]
|
||||
if app in SYSTEM_PERMS:
|
||||
logger.warning(f"Can't change 'protected' for system permission {permission}")
|
||||
else:
|
||||
update_settings["protected"] = protected
|
||||
|
||||
if show_tile is not None:
|
||||
if show_tile is True:
|
||||
if app in SYSTEM_PERMS:
|
||||
logger.warning(f"Can't change 'show_tile' for system permission {permission}")
|
||||
elif show_tile is True:
|
||||
if not existing_permission["url"]:
|
||||
logger.warning(
|
||||
m18n.n(
|
||||
|
@ -746,16 +752,22 @@ def _update_ldap_group_permission(
|
|||
permission=permission,
|
||||
)
|
||||
)
|
||||
show_tile = False
|
||||
update_settings["show_tile"] = False
|
||||
elif existing_permission["url"].startswith("re:"):
|
||||
logger.warning(
|
||||
m18n.n("show_tile_cant_be_enabled_for_regex", permission=permission)
|
||||
)
|
||||
show_tile = False
|
||||
update["showTile"] = [str(show_tile).upper()]
|
||||
update_settings["show_tile"] = False
|
||||
|
||||
if app not in SYSTEM_PERMS:
|
||||
perm_settings = app_setting(app, "_permissions") or {}
|
||||
if sub_permission not in perm_settings:
|
||||
perm_settings[sub_permission] = {}
|
||||
perm_settings[sub_permission].update(update_settings)
|
||||
app_setting(app, "_permissions", perm_settings)
|
||||
|
||||
try:
|
||||
ldap.update(f"cn={permission},ou=permission", update)
|
||||
ldap.update(f"cn={permission},ou=permission", update_ldap)
|
||||
except Exception as e:
|
||||
raise YunohostError("permission_update_failed", permission=permission, error=e)
|
||||
|
||||
|
@ -768,9 +780,6 @@ def _update_ldap_group_permission(
|
|||
|
||||
# Trigger app callbacks
|
||||
|
||||
app = permission.split(".")[0]
|
||||
sub_permission = permission.split(".")[1]
|
||||
|
||||
old_corresponding_users = set(existing_permission["corresponding_users"])
|
||||
new_corresponding_users = set(new_permission["corresponding_users"])
|
||||
|
||||
|
|
|
@ -288,6 +288,15 @@ def tools_regen_conf(
|
|||
names=[], with_diff=False, force=False, dry_run=False, list_pending=False
|
||||
):
|
||||
|
||||
# Make sure the permission infos are migrated before running the regenconf,
|
||||
# which may otherwise fuck things up because the slapd conf will be regenerated etc
|
||||
# We do this here because the regen-conf is called before the migration in debian/postinst
|
||||
if os.system(f"grep --quiet 0031_rework_permission_infos {MIGRATIONS_STATE_PATH}") != 0:
|
||||
try:
|
||||
tools_migrations_run(["0031_rework_permission_infos"])
|
||||
except Exception as e:
|
||||
logger.error(e)
|
||||
|
||||
from yunohost.regenconf import regen_conf
|
||||
return regen_conf(names, with_diff, force, dry_run, list_pending)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue