mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
Implement group management
This commit is contained in:
parent
7b8d668846
commit
bb892bb1a4
2 changed files with 346 additions and 31 deletions
|
@ -180,6 +180,7 @@
|
||||||
"dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}",
|
"dyndns_registration_failed": "Unable to register DynDNS domain: {error:s}",
|
||||||
"dyndns_domain_not_provided": "Dyndns provider {provider:s} cannot provide domain {domain:s}.",
|
"dyndns_domain_not_provided": "Dyndns provider {provider:s} cannot provide domain {domain:s}.",
|
||||||
"dyndns_unavailable": "Domain {domain:s} is not available.",
|
"dyndns_unavailable": "Domain {domain:s} is not available.",
|
||||||
|
"edit_group_not_allowed": "You are not allowed to edit the group {group:s}",
|
||||||
"executing_command": "Executing command '{command:s}'…",
|
"executing_command": "Executing command '{command:s}'…",
|
||||||
"executing_script": "Executing script '{script:s}'…",
|
"executing_script": "Executing script '{script:s}'…",
|
||||||
"extracting": "Extracting…",
|
"extracting": "Extracting…",
|
||||||
|
@ -207,6 +208,18 @@
|
||||||
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
|
"global_settings_unknown_type": "Unexpected situation, the setting {setting:s} appears to have the type {unknown_type:s} but it's not a type supported by the system.",
|
||||||
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_admin_password": "You are now about to define a new administration password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
||||||
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
"good_practices_about_user_password": "You are now about to define a new user password. The password should be at least 8 characters - though it is good practice to use longer password (i.e. a passphrase) and/or to use various kind of characters (uppercase, lowercase, digits and special characters).",
|
||||||
|
"group_alread_allowed": "Group '{group:s}' already allowed to access to permission '{permission:s}' for app '{app:s}'",
|
||||||
|
"group_alread_disallowed": "Group '{group:s}' already disallowed to access to permission '{permission:s}' for app '{app:s}'",
|
||||||
|
"group_name_already_exist": "Group {name:s} already exist",
|
||||||
|
"group_created": "Group creation success",
|
||||||
|
"group_creation_failed": "Group creation failed",
|
||||||
|
"group_deleted": "Group deleted",
|
||||||
|
"group_deletion_failed": "Group deletion failed",
|
||||||
|
"group_deletion_not_allowed": "You are not allowed to remove the main group of the user {user:s}",
|
||||||
|
"group_info_failed": "Group info failed",
|
||||||
|
"group_unknown": "Groupe {group:s} unknown",
|
||||||
|
"group_updated": "Groupe updated",
|
||||||
|
"group_update_failed": "groupe update failed",
|
||||||
"hook_exec_failed": "Script execution failed: {path:s}",
|
"hook_exec_failed": "Script execution failed: {path:s}",
|
||||||
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
|
"hook_exec_not_terminated": "Script execution hasn\u2019t terminated: {path:s}",
|
||||||
"hook_list_by_invalid": "Invalid property to list hook by",
|
"hook_list_by_invalid": "Invalid property to list hook by",
|
||||||
|
@ -244,13 +257,20 @@
|
||||||
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
|
"log_dyndns_subscribe": "Subscribe to a YunoHost subdomain '{}'",
|
||||||
"log_dyndns_update": "Update the ip associated with your YunoHost subdomain '{}'",
|
"log_dyndns_update": "Update the ip associated with your YunoHost subdomain '{}'",
|
||||||
"log_letsencrypt_cert_install": "Install Let's encrypt certificate on '{}' domain",
|
"log_letsencrypt_cert_install": "Install Let's encrypt certificate on '{}' domain",
|
||||||
|
"log_permission_add": "Add permission '{}' for app '{}'",
|
||||||
|
"log_permission_remove": "Remove permission '{}'",
|
||||||
|
"log_permission_update": "Update permission '{}' for app '{}'",
|
||||||
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
|
"log_selfsigned_cert_install": "Install self signed certificate on '{}' domain",
|
||||||
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
|
"log_letsencrypt_cert_renew": "Renew '{}' Let's encrypt certificate",
|
||||||
"log_service_enable": "Enable '{}' service",
|
"log_service_enable": "Enable '{}' service",
|
||||||
"log_service_regen_conf": "Regenerate system configurations '{}'",
|
"log_service_regen_conf": "Regenerate system configurations '{}'",
|
||||||
"log_user_create": "Add '{}' user",
|
"log_user_create": "Add '{}' user",
|
||||||
"log_user_delete": "Delete '{}' user",
|
"log_user_delete": "Delete '{}' user",
|
||||||
|
"log_user_group_add": "Add '{}' group",
|
||||||
|
"log_user_group_delete": "Delete '{}' group",
|
||||||
|
"log_user_group_update": "Update '{}' group",
|
||||||
"log_user_update": "Update information of '{}' user",
|
"log_user_update": "Update information of '{}' user",
|
||||||
|
"log_user_permission_add": "Update '{}' permission",
|
||||||
"log_tools_maindomain": "Make '{}' as main domain",
|
"log_tools_maindomain": "Make '{}' as main domain",
|
||||||
"log_tools_migrations_migrate_forward": "Migrate forward",
|
"log_tools_migrations_migrate_forward": "Migrate forward",
|
||||||
"log_tools_migrations_migrate_backward": "Migrate backward",
|
"log_tools_migrations_migrate_backward": "Migrate backward",
|
||||||
|
@ -370,11 +390,23 @@
|
||||||
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
|
"pattern_port_or_range": "Must be a valid port number (i.e. 0-65535) or range of ports (e.g. 100:200)",
|
||||||
"pattern_positive_number": "Must be a positive number",
|
"pattern_positive_number": "Must be a positive number",
|
||||||
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
|
"pattern_username": "Must be lower-case alphanumeric and underscore characters only",
|
||||||
|
"permission_already_clear": "Permission '{permission:s}' already clear for app {app:s}",
|
||||||
|
"permission_already_exist": "Permission '{permission:s}' for app {app:s} already exist",
|
||||||
|
"permission_created": "Permission '{permission:s}' for app {app:s} created",
|
||||||
|
"premission_creation_failled": "Permission creation failed",
|
||||||
|
"permission_deleted": "Permission '{permission:s}' for app {app:s} deleted",
|
||||||
|
"permission_deletion_failed": "Permission '{permission:s}' for app {app:s} deletion failed",
|
||||||
|
"permission_not_found": "Permission '{permission:s}' not found for application {app:s}",
|
||||||
|
"permission_name_not_valid": "Permission name '{permission:s}' not valid",
|
||||||
|
"permission_update_failed": "Permission update failed",
|
||||||
|
"permission_updated": "Permission '{permission:s}' for app {app:s} updated",
|
||||||
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
|
"port_already_closed": "Port {port:d} is already closed for {ip_version:s} connections",
|
||||||
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
|
"port_already_opened": "Port {port:d} is already opened for {ip_version:s} connections",
|
||||||
"port_available": "Port {port:d} is available",
|
"port_available": "Port {port:d} is available",
|
||||||
"port_unavailable": "Port {port:d} is not available",
|
"port_unavailable": "Port {port:d} is not available",
|
||||||
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
|
"recommend_to_add_first_user": "The post-install is finished but YunoHost needs at least one user to work correctly, you should add one using 'yunohost user create' or the admin interface.",
|
||||||
|
"remove_main_permission_not_allowed": "Removing the main permission is not allowed",
|
||||||
|
"remove_user_of_group_not_allowed": "You are not allowed to remove the user {user:s} in the group {group:s}",
|
||||||
"restore_action_required": "You must specify something to restore",
|
"restore_action_required": "You must specify something to restore",
|
||||||
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
|
"restore_already_installed_app": "An app is already installed with the id '{app:s}'",
|
||||||
"restore_app_failed": "Unable to restore the app '{app:s}'",
|
"restore_app_failed": "Unable to restore the app '{app:s}'",
|
||||||
|
@ -459,6 +491,7 @@
|
||||||
"ssowat_conf_updated": "The SSOwat configuration has been updated",
|
"ssowat_conf_updated": "The SSOwat configuration has been updated",
|
||||||
"ssowat_persistent_conf_read_error": "Error while reading SSOwat persistent configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
|
"ssowat_persistent_conf_read_error": "Error while reading SSOwat persistent configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
|
||||||
"ssowat_persistent_conf_write_error": "Error while saving SSOwat persistent configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
|
"ssowat_persistent_conf_write_error": "Error while saving SSOwat persistent configuration: {error:s}. Edit /etc/ssowat/conf.json.persistent file to fix the JSON syntax",
|
||||||
|
"system_groupname_exists": "Groupname already exists in the system group",
|
||||||
"system_upgraded": "The system has been upgraded",
|
"system_upgraded": "The system has been upgraded",
|
||||||
"system_username_exists": "Username already exists in the system users",
|
"system_username_exists": "Username already exists in the system users",
|
||||||
"unbackup_app": "App '{app:s}' will not be saved",
|
"unbackup_app": "App '{app:s}' will not be saved",
|
||||||
|
@ -474,12 +507,14 @@
|
||||||
"upnp_disabled": "UPnP has been disabled",
|
"upnp_disabled": "UPnP has been disabled",
|
||||||
"upnp_enabled": "UPnP has been enabled",
|
"upnp_enabled": "UPnP has been enabled",
|
||||||
"upnp_port_open_failed": "Unable to open UPnP ports",
|
"upnp_port_open_failed": "Unable to open UPnP ports",
|
||||||
|
"user_alread_in_group": "User {user:} already in group {group:s}",
|
||||||
"user_created": "The user has been created",
|
"user_created": "The user has been created",
|
||||||
"user_creation_failed": "Unable to create user",
|
"user_creation_failed": "Unable to create user",
|
||||||
"user_deleted": "The user has been deleted",
|
"user_deleted": "The user has been deleted",
|
||||||
"user_deletion_failed": "Unable to delete user",
|
"user_deletion_failed": "Unable to delete user",
|
||||||
"user_home_creation_failed": "Unable to create user home folder",
|
"user_home_creation_failed": "Unable to create user home folder",
|
||||||
"user_info_failed": "Unable to retrieve user information",
|
"user_info_failed": "Unable to retrieve user information",
|
||||||
|
"user_not_in_group": "User {user:s} not in group {group:s}",
|
||||||
"user_unknown": "Unknown user: {user:s}",
|
"user_unknown": "Unknown user: {user:s}",
|
||||||
"user_update_failed": "Unable to update user",
|
"user_update_failed": "Unable to update user",
|
||||||
"user_updated": "The user has been updated",
|
"user_updated": "The user has been updated",
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
import pwd
|
import pwd
|
||||||
|
import grp
|
||||||
import json
|
import json
|
||||||
import crypt
|
import crypt
|
||||||
import random
|
import random
|
||||||
|
@ -123,7 +124,8 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
|
||||||
# Validate uniqueness of username and mail in LDAP
|
# Validate uniqueness of username and mail in LDAP
|
||||||
auth.validate_uniqueness({
|
auth.validate_uniqueness({
|
||||||
'uid': username,
|
'uid': username,
|
||||||
'mail': mail
|
'mail': mail,
|
||||||
|
'cn': username
|
||||||
})
|
})
|
||||||
|
|
||||||
# Validate uniqueness of username in system users
|
# Validate uniqueness of username in system users
|
||||||
|
@ -150,7 +152,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
|
||||||
|
|
||||||
# Get random UID/GID
|
# Get random UID/GID
|
||||||
all_uid = {x.pw_uid for x in pwd.getpwall()}
|
all_uid = {x.pw_uid for x in pwd.getpwall()}
|
||||||
all_gid = {x.pw_gid for x in pwd.getpwall()}
|
all_gid = {x.gr_gid for x in grp.getgrall()}
|
||||||
|
|
||||||
uid_guid_found = False
|
uid_guid_found = False
|
||||||
while not uid_guid_found:
|
while not uid_guid_found:
|
||||||
|
@ -160,7 +162,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
|
||||||
# Adapt values for LDAP
|
# Adapt values for LDAP
|
||||||
fullname = '%s %s' % (firstname, lastname)
|
fullname = '%s %s' % (firstname, lastname)
|
||||||
attr_dict = {
|
attr_dict = {
|
||||||
'objectClass': ['mailAccount', 'inetOrgPerson', 'posixAccount'],
|
'objectClass': ['mailAccount', 'inetOrgPerson', 'posixAccount', 'userPermissionYnh'],
|
||||||
'givenName': firstname,
|
'givenName': firstname,
|
||||||
'sn': lastname,
|
'sn': lastname,
|
||||||
'displayName': fullname,
|
'displayName': fullname,
|
||||||
|
@ -201,25 +203,26 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
|
||||||
# Invalidate passwd to take user creation into account
|
# Invalidate passwd to take user creation into account
|
||||||
subprocess.call(['nscd', '-i', 'passwd'])
|
subprocess.call(['nscd', '-i', 'passwd'])
|
||||||
|
|
||||||
# Update SFTP user group
|
try:
|
||||||
memberlist = auth.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid']
|
# Attempt to create user home folder
|
||||||
memberlist.append(username)
|
subprocess.check_call(
|
||||||
if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}):
|
['su', '-', username, '-c', "''"])
|
||||||
try:
|
except subprocess.CalledProcessError:
|
||||||
# Attempt to create user home folder
|
if not os.path.isdir('/home/{0}'.format(username)):
|
||||||
subprocess.check_call(
|
logger.warning(m18n.n('user_home_creation_failed'),
|
||||||
['su', '-', username, '-c', "''"])
|
exc_info=1)
|
||||||
except subprocess.CalledProcessError:
|
app_ssowatconf(auth)
|
||||||
if not os.path.isdir('/home/{0}'.format(username)):
|
# TODO: Send a welcome mail to user
|
||||||
logger.warning(m18n.n('user_home_creation_failed'),
|
logger.success(m18n.n('user_created'))
|
||||||
exc_info=1)
|
# Create group for user and add to group 'ALL'
|
||||||
app_ssowatconf(auth)
|
user_group_add(auth, groupname=username, gid=uid)
|
||||||
# TODO: Send a welcome mail to user
|
user_group_update(auth, groupname=username, add_user=username, force=True)
|
||||||
logger.success(m18n.n('user_created'))
|
user_group_update(auth, 'ALL', add_user=username, force=True)
|
||||||
hook_callback('post_user_create',
|
|
||||||
args=[username, mail, password, firstname, lastname])
|
|
||||||
|
|
||||||
return {'fullname': fullname, 'username': username, 'mail': mail}
|
hook_callback('post_user_create',
|
||||||
|
args=[username, mail, password, firstname, lastname])
|
||||||
|
|
||||||
|
return {'fullname': fullname, 'username': username, 'mail': mail}
|
||||||
|
|
||||||
raise YunohostError('user_creation_failed')
|
raise YunohostError('user_creation_failed')
|
||||||
|
|
||||||
|
@ -242,19 +245,24 @@ def user_delete(operation_logger, auth, username, purge=False):
|
||||||
# Invalidate passwd to take user deletion into account
|
# Invalidate passwd to take user deletion into account
|
||||||
subprocess.call(['nscd', '-i', 'passwd'])
|
subprocess.call(['nscd', '-i', 'passwd'])
|
||||||
|
|
||||||
# Update SFTP user group
|
if purge:
|
||||||
memberlist = auth.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid']
|
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
|
||||||
try:
|
|
||||||
memberlist.remove(username)
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}):
|
|
||||||
if purge:
|
|
||||||
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
|
|
||||||
subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)])
|
|
||||||
else:
|
else:
|
||||||
raise YunohostError('user_deletion_failed')
|
raise YunohostError('user_deletion_failed')
|
||||||
|
|
||||||
|
user_group_delete(auth, username, force=True)
|
||||||
|
|
||||||
|
group_list = auth.search('ou=groups,dc=yunohost,dc=org',
|
||||||
|
'(&(objectclass=groupOfNamesYnh)(memberUid=%s))'
|
||||||
|
% username, ['cn'])
|
||||||
|
for group in group_list:
|
||||||
|
user_list = auth.search('ou=groups,dc=yunohost,dc=org',
|
||||||
|
'cn=' + group['cn'][0],
|
||||||
|
['memberUid'])[0]
|
||||||
|
user_list['memberUid'].remove(username)
|
||||||
|
if not auth.update('cn=%s,ou=groups' % group['cn'][0], user_list):
|
||||||
|
raise YunohostError('group_update_failed')
|
||||||
|
|
||||||
app_ssowatconf(auth)
|
app_ssowatconf(auth)
|
||||||
|
|
||||||
hook_callback('post_user_delete', args=[username, purge])
|
hook_callback('post_user_delete', args=[username, purge])
|
||||||
|
@ -462,6 +470,278 @@ def user_info(auth, username):
|
||||||
else:
|
else:
|
||||||
raise YunohostError('user_info_failed')
|
raise YunohostError('user_info_failed')
|
||||||
|
|
||||||
|
#
|
||||||
|
# Group subcategory
|
||||||
|
#
|
||||||
|
#
|
||||||
|
def user_group_list(auth, fields=None):
|
||||||
|
"""
|
||||||
|
List users
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
filter -- LDAP filter used to search
|
||||||
|
offset -- Starting number for user fetching
|
||||||
|
limit -- Maximum number of user fetched
|
||||||
|
fields -- fields to fetch
|
||||||
|
|
||||||
|
"""
|
||||||
|
group_attr = {
|
||||||
|
'cn' : 'groupname',
|
||||||
|
'member' : 'members',
|
||||||
|
'permission' : 'permission'
|
||||||
|
}
|
||||||
|
attrs = ['cn']
|
||||||
|
groups = {}
|
||||||
|
|
||||||
|
if fields:
|
||||||
|
keys = group_attr.keys()
|
||||||
|
for attr in fields:
|
||||||
|
if attr in keys:
|
||||||
|
attrs.append(attr)
|
||||||
|
else:
|
||||||
|
raise MoulinetteError(errno.EINVAL,
|
||||||
|
m18n.n('field_invalid', attr))
|
||||||
|
else:
|
||||||
|
attrs = ['cn', 'member']
|
||||||
|
|
||||||
|
result = auth.search('ou=groups,dc=yunohost,dc=org',
|
||||||
|
'(objectclass=groupOfNamesYnh)',
|
||||||
|
attrs)
|
||||||
|
|
||||||
|
for group in result:
|
||||||
|
# The group "admins" should be hidden for the user
|
||||||
|
if group_attr['cn'] == "admins":
|
||||||
|
continue
|
||||||
|
entry = {}
|
||||||
|
for attr, values in group.items():
|
||||||
|
if values:
|
||||||
|
if attr == "member":
|
||||||
|
entry[group_attr[attr]] = []
|
||||||
|
for v in values:
|
||||||
|
entry[group_attr[attr]].append(v.split("=")[1].split(",")[0])
|
||||||
|
elif attr == "permission":
|
||||||
|
entry[group_attr[attr]] = {}
|
||||||
|
for v in values:
|
||||||
|
permission = v.split("=")[1].split(",")[0].split(".")[0]
|
||||||
|
pType = v.split("=")[1].split(",")[0].split(".")[1]
|
||||||
|
if permission in entry[group_attr[attr]]:
|
||||||
|
entry[group_attr[attr]][permission].append(pType)
|
||||||
|
else:
|
||||||
|
entry[group_attr[attr]][permission] = [pType]
|
||||||
|
else:
|
||||||
|
entry[group_attr[attr]] = values[0]
|
||||||
|
|
||||||
|
groupname = entry[group_attr['cn']]
|
||||||
|
groups[groupname] = entry
|
||||||
|
return {'groups' : groups}
|
||||||
|
|
||||||
|
|
||||||
|
@is_unit_operation([('groupname', 'user')])
|
||||||
|
def user_group_add(operation_logger, auth, groupname,gid=None):
|
||||||
|
"""
|
||||||
|
Create group
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
groupname -- Must be unique
|
||||||
|
|
||||||
|
"""
|
||||||
|
from yunohost.app import app_ssowatconf
|
||||||
|
from yunohost.permission import _permission_sync_to_user
|
||||||
|
|
||||||
|
operation_logger.start()
|
||||||
|
|
||||||
|
# Validate uniqueness of groupname in LDAP
|
||||||
|
conflict = auth.get_conflict({
|
||||||
|
'cn': groupname
|
||||||
|
}, base_dn='ou=groups,dc=yunohost,dc=org')
|
||||||
|
if conflict:
|
||||||
|
raise MoulinetteError(errno.EEXIST, m18n.n('group_name_already_exist', name=groupname))
|
||||||
|
|
||||||
|
# Validate uniqueness of groupname in system group
|
||||||
|
all_existing_groupnames = {x.gr_name for x in grp.getgrall()}
|
||||||
|
if groupname in all_existing_groupnames:
|
||||||
|
raise MoulinetteError(errno.EEXIST, m18n.n('system_groupname_exists'))
|
||||||
|
|
||||||
|
if not gid:
|
||||||
|
# Get random GID
|
||||||
|
all_gid = {x.gr_gid for x in grp.getgrall()}
|
||||||
|
|
||||||
|
uid_guid_found = False
|
||||||
|
while not uid_guid_found:
|
||||||
|
gid = str(random.randint(200, 99999))
|
||||||
|
uid_guid_found = gid not in all_gid
|
||||||
|
|
||||||
|
attr_dict = {
|
||||||
|
'objectClass': ['top', 'groupOfNamesYnh', 'posixGroup'],
|
||||||
|
'cn': groupname,
|
||||||
|
'gidNumber': gid,
|
||||||
|
}
|
||||||
|
|
||||||
|
if auth.add('cn=%s,ou=groups' % groupname, attr_dict):
|
||||||
|
_permission_sync_to_user(auth)
|
||||||
|
app_ssowatconf(auth)
|
||||||
|
logger.success(m18n.n('group_created'))
|
||||||
|
return {'name': groupname}
|
||||||
|
|
||||||
|
raise MoulinetteError(169, m18n.n('group_creation_failed'))
|
||||||
|
|
||||||
|
|
||||||
|
@is_unit_operation([('groupname', 'user')])
|
||||||
|
def user_group_delete(operation_logger, auth, groupname, force=False):
|
||||||
|
"""
|
||||||
|
Delete user
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
groupname -- Groupname to delete
|
||||||
|
|
||||||
|
"""
|
||||||
|
from yunohost.app import app_ssowatconf
|
||||||
|
from yunohost.permission import _permission_sync_to_user
|
||||||
|
|
||||||
|
if not force and (groupname == 'ALL' or groupname == 'admins' or groupname in user_list(auth, ['uid'])['users']):
|
||||||
|
raise MoulinetteError(errno.EPERM, m18n.n('group_deletion_not_allowed', user=groupname))
|
||||||
|
|
||||||
|
operation_logger.start()
|
||||||
|
if not auth.remove('cn=%s,ou=groups' % groupname):
|
||||||
|
raise MoulinetteError(169, m18n.n('group_deletion_failed'))
|
||||||
|
|
||||||
|
_permission_sync_to_user(auth)
|
||||||
|
app_ssowatconf(auth)
|
||||||
|
logger.success(m18n.n('group_deleted'))
|
||||||
|
|
||||||
|
|
||||||
|
@is_unit_operation([('groupname', 'user')])
|
||||||
|
def user_group_update(operation_logger, auth, groupname, add_user=None, remove_user=None, force=False):
|
||||||
|
"""
|
||||||
|
Update user informations
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
groupname -- Groupname to update
|
||||||
|
add_user -- User to add in group
|
||||||
|
remove_user -- User to remove in group
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from yunohost.app import app_ssowatconf
|
||||||
|
from yunohost.permission import _permission_sync_to_user
|
||||||
|
|
||||||
|
attrs_to_fetch = ['member']
|
||||||
|
|
||||||
|
if (groupname == 'ALL' or groupname == 'admins') and not force:
|
||||||
|
raise MoulinetteError(errno.EINVAL, m18n.n('edit_group_not_allowed', group=groupname))
|
||||||
|
|
||||||
|
# Populate group informations
|
||||||
|
result = auth.search(base='ou=groups,dc=yunohost,dc=org',
|
||||||
|
filter='cn=' + groupname, attrs=attrs_to_fetch)
|
||||||
|
if not result:
|
||||||
|
raise MoulinetteError(errno.EINVAL, m18n.n('group_unknown', group=groupname))
|
||||||
|
group = result[0]
|
||||||
|
|
||||||
|
new_group_list = {'member': set(), 'memberUid': set()}
|
||||||
|
if 'member' in group:
|
||||||
|
new_group_list['member'] = set(group['member'])
|
||||||
|
else:
|
||||||
|
group['member'] = []
|
||||||
|
|
||||||
|
user_l = user_list(auth, ['uid'])['users']
|
||||||
|
|
||||||
|
if add_user:
|
||||||
|
if not isinstance(add_user, list):
|
||||||
|
add_user = [add_user]
|
||||||
|
for user in add_user:
|
||||||
|
if not user in user_l:
|
||||||
|
raise MoulinetteError(errno.EINVAL, m18n.n('user_unknown', user=user))
|
||||||
|
userDN = "uid=" + user + ",ou=users,dc=yunohost,dc=org"
|
||||||
|
if userDN in group['member']:
|
||||||
|
logger.warning(m18n.n('user_alread_in_group', user=user, group=groupname))
|
||||||
|
new_group_list['member'].add(userDN)
|
||||||
|
|
||||||
|
if remove_user:
|
||||||
|
if not isinstance(remove_user, list):
|
||||||
|
remove_user = [remove_user]
|
||||||
|
for user in remove_user:
|
||||||
|
userDN = "uid=" + user + ",ou=users,dc=yunohost,dc=org"
|
||||||
|
if user == groupname:
|
||||||
|
raise MoulinetteError(errno.EINVAL,
|
||||||
|
m18n.n('remove_user_of_group_not_allowed', user=user, group=groupname))
|
||||||
|
if 'member' in group and userDN in group['member']:
|
||||||
|
new_group_list['member'].remove(userDN)
|
||||||
|
else:
|
||||||
|
logger.warning(m18n.n('user_not_in_group', user=user, group=groupname))
|
||||||
|
|
||||||
|
# Sychronise memberUid with member (to keep the posix group structure)
|
||||||
|
# In posixgroup the main group of each user is only written in the gid number of the user
|
||||||
|
for member in new_group_list['member']:
|
||||||
|
member_Uid = member.split("=")[1].split(",")[0]
|
||||||
|
# Don't add main user in the group.
|
||||||
|
# Note that in the Unix system the main user of the group is linked by the gid in the user attribute.
|
||||||
|
# So the main user need to be not in the memberUid list of his own group.
|
||||||
|
if member_Uid != groupname:
|
||||||
|
new_group_list['memberUid'].add(member_Uid)
|
||||||
|
|
||||||
|
operation_logger.start()
|
||||||
|
|
||||||
|
if new_group_list['member'] != set(group['member']):
|
||||||
|
if not auth.update('cn=%s,ou=groups' % groupname, new_group_list):
|
||||||
|
raise MoulinetteError(169, m18n.n('group_update_failed'))
|
||||||
|
|
||||||
|
_permission_sync_to_user(auth)
|
||||||
|
logger.success(m18n.n('group_updated'))
|
||||||
|
app_ssowatconf(auth)
|
||||||
|
return user_group_info(auth, groupname)
|
||||||
|
|
||||||
|
|
||||||
|
def user_group_info(auth, groupname):
|
||||||
|
"""
|
||||||
|
Get user informations
|
||||||
|
|
||||||
|
Keyword argument:
|
||||||
|
groupname -- Groupname to get informations
|
||||||
|
|
||||||
|
"""
|
||||||
|
group_attrs = [
|
||||||
|
'cn', 'member', 'permission'
|
||||||
|
]
|
||||||
|
result = auth.search('ou=groups,dc=yunohost,dc=org', "cn=" + groupname, group_attrs)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
raise MoulinetteError(errno.EINVAL, m18n.n('group_unknown', group=groupname))
|
||||||
|
else:
|
||||||
|
group = result[0]
|
||||||
|
|
||||||
|
result_dict = {
|
||||||
|
'groupname': group['cn'][0],
|
||||||
|
'member': None
|
||||||
|
}
|
||||||
|
if 'member' in group:
|
||||||
|
result_dict['member'] = {m.split("=")[1].split(",")[0] for m in group['member']}
|
||||||
|
return result_dict
|
||||||
|
|
||||||
|
#
|
||||||
|
# Permission subcategory
|
||||||
|
#
|
||||||
|
#
|
||||||
|
import yunohost.permission
|
||||||
|
|
||||||
|
def user_permission_list(auth, app=None, permission=None, username=None, group=None):
|
||||||
|
return yunohost.permission.user_permission_list(auth, app, permission, username, group)
|
||||||
|
|
||||||
|
@is_unit_operation([('app', 'user')])
|
||||||
|
def user_permission_add(operation_logger, auth, app, permission="main", username=None, group=None):
|
||||||
|
return yunohost.permission.user_permission_update(operation_logger, auth, app, permission=permission,
|
||||||
|
add_username=username, add_group=group,
|
||||||
|
del_username=None, del_group=None)
|
||||||
|
|
||||||
|
@is_unit_operation([('app', 'user')])
|
||||||
|
def user_permission_remove(operation_logger, auth, app, permission="main", username=None, group=None):
|
||||||
|
return yunohost.permission.user_permission_update(operation_logger, auth, app, permission=permission,
|
||||||
|
add_username=None, add_group=None,
|
||||||
|
del_username=username, del_group=group)
|
||||||
|
|
||||||
|
@is_unit_operation([('app', 'user')])
|
||||||
|
def user_permission_clear(operation_logger, auth, app, permission=None):
|
||||||
|
return yunohost.permission.user_permission_clear(operation_logger, auth, app, permission)
|
||||||
|
|
||||||
#
|
#
|
||||||
# SSH subcategory
|
# SSH subcategory
|
||||||
#
|
#
|
||||||
|
|
Loading…
Add table
Reference in a new issue