Skip to content

Commit 30015ca

Browse files
committed
app/permissions: Move permissions data out of LDAP
1 parent 505e3db commit 30015ca

File tree

4 files changed

+149
-91
lines changed

4 files changed

+149
-91
lines changed

conf/slapd/db_init.ldif

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -68,28 +68,16 @@ groupPermission: cn=all_users,ou=groups,dc=yunohost,dc=org
6868
cn: mail.main
6969
objectClass: posixGroup
7070
objectClass: permissionYnh
71-
isProtected: TRUE
72-
label: E-mail
7371
gidNumber: 5001
74-
showTile: FALSE
75-
authHeader: FALSE
7672

7773
dn: cn=ssh.main,ou=permission,dc=yunohost,dc=org
7874
cn: ssh.main
7975
objectClass: posixGroup
8076
objectClass: permissionYnh
81-
isProtected: TRUE
82-
label: SSH
8377
gidNumber: 5003
84-
showTile: FALSE
85-
authHeader: FALSE
8678

8779
dn: cn=sftp.main,ou=permission,dc=yunohost,dc=org
8880
cn: sftp.main
8981
objectClass: posixGroup
9082
objectClass: permissionYnh
91-
isProtected: TRUE
92-
label: SFTP
9383
gidNumber: 5004
94-
showTile: FALSE
95-
authHeader: FALSE

conf/slapd/permission.ldif

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,6 @@ olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.2 NAME 'groupPermission'
1414
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.3 NAME 'inheritPermission'
1515
DESC 'YunoHost permission for user on permission side'
1616
SUP distinguishedName )
17-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.4 NAME 'URL'
18-
DESC 'YunoHost permission main URL'
19-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
20-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.5 NAME 'additionalUrls'
21-
DESC 'YunoHost permission additionnal URL'
22-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
23-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.6 NAME 'authHeader'
24-
DESC 'YunoHost application, enable authentication header'
25-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
26-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.7 NAME 'label'
27-
DESC 'YunoHost permission label, also used for the tile name in the SSO'
28-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} SINGLE-VALUE )
29-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.8 NAME 'showTile'
30-
DESC 'YunoHost application, show/hide the tile in the SSO for this permission'
31-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
32-
olcAttributeTypes: ( 1.3.6.1.4.1.17953.9.1.9 NAME 'isProtected'
33-
DESC 'YunoHost application permission protection'
34-
SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE )
3517
# OBJECTCLASS
3618
# For Applications
3719
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'
4123
olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.2 NAME 'permissionYnh'
4224
DESC 'a YunoHost application'
4325
SUP top AUXILIARY
44-
MUST ( cn $ authHeader $ label $ showTile $ isProtected )
45-
MAY ( groupPermission $ inheritPermission $ URL $ additionalUrls ) )
26+
MUST ( cn )
27+
MAY ( groupPermission $ inheritPermission ) )
4628
# For User
4729
olcObjectClasses: ( 1.3.6.1.4.1.17953.9.2.3 NAME 'userPermissionYnh'
4830
DESC 'a YunoHost application'
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from logging import getLogger
2+
3+
from yunohost.tools import Migration
4+
from yunohost.permission import permission_sync_to_user
5+
from yunohost.app import app_setting
6+
7+
logger = getLogger("yunohost.migration")
8+
9+
###################################################
10+
# Tools used also for restoration
11+
###################################################
12+
13+
14+
class MyMigration(Migration):
15+
16+
introduced_in_version = "12.1"
17+
dependencies = []
18+
19+
ldap_migration_started = False
20+
21+
@Migration.ldap_migration
22+
def run(self, *args):
23+
24+
self.ldap_migration_started = True
25+
26+
permissions_per_app = self.read_legacy_permissions_per_app()
27+
for app, permissions in permissions_per_app.items():
28+
print(app)
29+
print(permissions)
30+
app_setting(app, "_permissions", permissions)
31+
32+
permission_sync_to_user()
33+
34+
# FIXME : dummy excepton to trigger the rollback while debugging everything etc
35+
raise Exception
36+
37+
def run_after_system_restore(self):
38+
self.run()
39+
40+
def read_legacy_permissions_per_app(self):
41+
42+
from yunohost.utils.ldap import _get_ldap_interface
43+
SYSTEM_PERMS = ["mail", "sftp", "ssh"]
44+
45+
ldap = _get_ldap_interface()
46+
permissions_infos = ldap.search(
47+
"ou=permission",
48+
"(objectclass=permissionYnh)",
49+
[
50+
"cn",
51+
"URL",
52+
"additionalUrls",
53+
"authHeader",
54+
"label",
55+
"showTile",
56+
"isProtected",
57+
],
58+
)
59+
60+
permissions_per_app = {}
61+
for infos in permissions_infos:
62+
app, name = infos["cn"][0].split(".")
63+
64+
if app in SYSTEM_PERMS:
65+
continue
66+
67+
if app not in permissions_per_app:
68+
permissions_per_app[app] = {}
69+
70+
permissions_per_app[app][name] = {
71+
"label": infos.get("label", [None])[0],
72+
"show_tile": infos.get("showTile", [False])[0] == "TRUE",
73+
"auth_header": infos.get("authHeader", [False])[0] == "TRUE",
74+
"protected": infos.get("isProtected", [False])[0] == "TRUE",
75+
"url": infos.get("URL", [None])[0],
76+
"additional_urls": infos.get("additionalUrls", []),
77+
}
78+
79+
return permissions_per_app

src/permission.py

Lines changed: 68 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,13 @@ def user_permission_list(
4949
from yunohost.utils.ldap import _get_ldap_interface, _ldap_path_extract
5050

5151
ldap = _get_ldap_interface()
52-
permissions_infos = ldap.search(
52+
ldap_permissions_infos = ldap.search(
5353
"ou=permission",
5454
"(objectclass=permissionYnh)",
5555
[
5656
"cn",
5757
"groupPermission",
5858
"inheritPermission",
59-
"URL",
60-
"additionalUrls",
61-
"authHeader",
62-
"label",
63-
"showTile",
64-
"isProtected",
6559
],
6660
)
6761

@@ -78,30 +72,29 @@ def user_permission_list(
7872
}
7973

8074
permissions = {}
81-
for infos in permissions_infos:
75+
for infos in ldap_permissions_infos:
8276
name = infos["cn"][0]
83-
app = name.split(".")[0]
77+
app, subperm = name.split(".")
8478

8579
if ignore_system_perms and app in SYSTEM_PERMS:
8680
continue
8781
if filter_ and app not in apps:
8882
continue
8983

9084
perm = {}
91-
perm["allowed"] = [
92-
_ldap_path_extract(p, "cn") for p in infos.get("groupPermission", [])
93-
]
94-
95-
if full:
96-
perm["corresponding_users"] = [
97-
_ldap_path_extract(p, "uid") for p in infos.get("inheritPermission", [])
98-
]
99-
perm["auth_header"] = infos.get("authHeader", [False])[0] == "TRUE"
100-
perm["label"] = infos.get("label", [None])[0]
101-
perm["show_tile"] = infos.get("showTile", [False])[0] == "TRUE"
102-
perm["protected"] = infos.get("isProtected", [False])[0] == "TRUE"
103-
perm["url"] = infos.get("URL", [None])[0]
104-
perm["additional_urls"] = infos.get("additionalUrls", [])
85+
if full and app not in SYSTEM_PERMS:
86+
# Default stuff
87+
perm = {
88+
"url": None,
89+
"additional_urls": [],
90+
"auth_header": True,
91+
"show_tile": None, # To be automagically set to True by default if an url is defined and show_tile not provided
92+
"protected": False,
93+
}
94+
perm_settings = (app_setting(app, "_permissions") or {}).get(subperm, {})
95+
perm.update(perm_settings)
96+
if perm["show_tile"] is None and perm["url"] is not None:
97+
perm["show_tile"] = True
10598

10699
if absolute_urls:
107100
app_base_path = (
@@ -113,6 +106,14 @@ def user_permission_list(
113106
for url in perm["additional_urls"]
114107
]
115108

109+
perm["allowed"] = [
110+
_ldap_path_extract(p, "cn") for p in infos.get("groupPermission", [])
111+
]
112+
if full:
113+
perm["corresponding_users"] = [
114+
_ldap_path_extract(p, "uid") for p in infos.get("inheritPermission", [])
115+
]
116+
116117
permissions[name] = perm
117118

118119
# Make sure labels for sub-permissions are the form " Applabel (Sublabel) "
@@ -414,16 +415,6 @@ def permission_create(
414415
"objectClass": ["top", "permissionYnh", "posixGroup"],
415416
"cn": str(permission),
416417
"gidNumber": gid,
417-
"authHeader": ["TRUE"],
418-
"label": [
419-
str(label) if label else (subperm if subperm != "main" else app.title())
420-
],
421-
"showTile": [
422-
"FALSE"
423-
], # Dummy value, it will be fixed when we call '_update_ldap_group_permission'
424-
"isProtected": [
425-
"FALSE"
426-
], # Dummy value, it will be fixed when we call '_update_ldap_group_permission'
427418
}
428419

429420
if allowed is not None:
@@ -446,6 +437,8 @@ def permission_create(
446437
"permission_creation_failed", permission=permission, error=e
447438
)
448439

440+
label = str(label) if label else (subperm if subperm != "main" else app.title())
441+
449442
try:
450443
permission_url(
451444
permission,
@@ -463,6 +456,7 @@ def permission_create(
463456
protected=protected,
464457
sync_perm=sync_perm,
465458
)
459+
466460
except Exception:
467461
permission_delete(permission, force=True)
468462
raise
@@ -496,15 +490,15 @@ def permission_url(
496490
clear_urls -- (optional) Clean all urls (url and additional_urls)
497491
"""
498492
from yunohost.app import app_setting
499-
from yunohost.utils.ldap import _get_ldap_interface
500-
501-
ldap = _get_ldap_interface()
502493

503494
# By default, manipulate main permission
504495
if "." not in permission:
505496
permission = permission + ".main"
506497

507-
app = permission.split(".")[0]
498+
app, sub_permission = permission.split(".")
499+
500+
if app in SYSTEM_PERMS:
501+
logger.warning(f"Cannot change urls / auth_header for system perm {permission}")
508502

509503
if url or add_url:
510504
domain = app_setting(app, "domain")
@@ -573,19 +567,20 @@ def permission_url(
573567

574568
# Actually commit the change
575569

576-
operation_logger.related_to.append(("app", permission.split(".")[0]))
570+
operation_logger.related_to.append(("app", app))
577571
operation_logger.start()
578572

579573
try:
580-
ldap.update(
581-
f"cn={permission},ou=permission",
582-
{
583-
"URL": [url] if url is not None else [],
584-
"additionalUrls": new_additional_urls,
585-
"authHeader": [str(auth_header).upper()],
586-
"showTile": [str(show_tile).upper()],
587-
},
588-
)
574+
perm_settings = app_setting(app, "_permissions", {})
575+
if sub_permission not in perm_settings:
576+
perm_settings[sub_permission] = {}
577+
perm_settings[sub_permission].update({
578+
"url": url,
579+
"additional_urls": new_additional_urls,
580+
"auth_header": auth_header,
581+
"show_tile": show_tile,
582+
})
583+
app_setting(app, "_permissions", perm_settings)
589584
except Exception as e:
590585
raise YunohostError("permission_update_failed", permission=permission, error=e)
591586

@@ -714,48 +709,65 @@ def _update_ldap_group_permission(
714709
- the 'allowed' list contains *existing* groups.
715710
"""
716711

712+
from yunohost.app import app_setting
717713
from yunohost.hook import hook_callback
718714
from yunohost.utils.ldap import _get_ldap_interface
719715

720716
ldap = _get_ldap_interface()
721717

718+
app, sub_permission = permission.split(".")
722719
existing_permission = user_permission_info(permission)
723720

724-
update = {}
721+
update_ldap = {}
722+
update_settings = {}
725723

726724
if allowed is not None:
727725
allowed = [allowed] if not isinstance(allowed, list) else allowed
728726
# Guarantee uniqueness of values in allowed, which would otherwise make ldap.update angry.
729727
allowed = set(allowed)
730-
update["groupPermission"] = [
728+
update_ldap["groupPermission"] = [
731729
"cn=" + g + ",ou=groups,dc=yunohost,dc=org" for g in allowed
732730
]
733731

734732
if label is not None:
735-
update["label"] = [str(label)]
733+
if app in SYSTEM_PERMS:
734+
logger.warning(f"Can't change 'label' for system permission {permission}")
735+
else:
736+
update_settings["label"] = str(label)
736737

737738
if protected is not None:
738-
update["isProtected"] = [str(protected).upper()]
739+
if app in SYSTEM_PERMS:
740+
logger.warning(f"Can't change 'protected' for system permission {permission}")
741+
else:
742+
update_settings["protected"] = protected
739743

740744
if show_tile is not None:
741-
if show_tile is True:
745+
if app in SYSTEM_PERMS:
746+
logger.warning(f"Can't change 'show_tile' for system permission {permission}")
747+
elif show_tile is True:
742748
if not existing_permission["url"]:
743749
logger.warning(
744750
m18n.n(
745751
"show_tile_cant_be_enabled_for_url_not_defined",
746752
permission=permission,
747753
)
748754
)
749-
show_tile = False
755+
update_settings["show_tile"] = False
750756
elif existing_permission["url"].startswith("re:"):
751757
logger.warning(
752758
m18n.n("show_tile_cant_be_enabled_for_regex", permission=permission)
753759
)
754-
show_tile = False
755-
update["showTile"] = [str(show_tile).upper()]
760+
update_settings["show_tile"] = False
761+
762+
if app not in SYSTEM_PERMS:
763+
perm_settings = app_setting(app, "_permissions", {})
764+
if sub_permission not in perm_settings:
765+
perm_settings[sub_permission] = {}
766+
perm_settings[sub_permission].update(update_settings)
767+
app_setting(app, "_permissions", perm_settings)
756768

757769
try:
758-
ldap.update(f"cn={permission},ou=permission", update)
770+
ldap.update(f"cn={permission},ou=permission", update_ldap)
759771
except Exception as e:
760772
raise YunohostError("permission_update_failed", permission=permission, error=e)
761773

@@ -768,9 +780,6 @@ def _update_ldap_group_permission(
768780

769781
# Trigger app callbacks
770782

771-
app = permission.split(".")[0]
772-
sub_permission = permission.split(".")[1]
773-
774783
old_corresponding_users = set(existing_permission["corresponding_users"])
775784
new_corresponding_users = set(new_permission["corresponding_users"])
776785

0 commit comments

Comments
 (0)