Merge pull request #721 from YunoHost/authenticate-as-root

[enh] Simplify the whole LDAP interface thing
This commit is contained in:
Alexandre Aubin 2019-05-22 17:51:04 +02:00 committed by GitHub
commit b3d29238c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 279 additions and 326 deletions

View file

@ -43,13 +43,8 @@ _global:
parameters: parameters:
uri: ldap://localhost:389 uri: ldap://localhost:389
base_dn: dc=yunohost,dc=org base_dn: dc=yunohost,dc=org
user_rdn: cn=admin user_rdn: cn=admin,dc=yunohost,dc=org
ldap-anonymous: argument_auth: false
vendor: ldap
parameters:
uri: ldap://localhost:389
base_dn: dc=yunohost,dc=org
argument_auth: true
arguments: arguments:
-v: -v:
full: --version full: --version
@ -70,9 +65,6 @@ user:
list: list:
action_help: List users action_help: List users
api: GET /users api: GET /users
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
--fields: --fields:
help: fields to fetch help: fields to fetch
@ -82,8 +74,6 @@ user:
create: create:
action_help: Create user action_help: Create user
api: POST /users api: POST /users
configuration:
authenticate: all
arguments: arguments:
username: username:
help: The unique username to create help: The unique username to create
@ -140,8 +130,6 @@ user:
delete: delete:
action_help: Delete user action_help: Delete user
api: DELETE /users/<username> api: DELETE /users/<username>
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username to delete help: Username to delete
@ -155,8 +143,6 @@ user:
update: update:
action_help: Update user informations action_help: Update user informations
api: PUT /users/<username> api: PUT /users/<username>
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username to update help: Username to update
@ -209,9 +195,6 @@ user:
info: info:
action_help: Get user information action_help: Get user information
api: GET /users/<username> api: GET /users/<username>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
username: username:
help: Username or email to get information help: Username or email to get information
@ -225,8 +208,6 @@ user:
allow: allow:
action_help: Allow the user to uses ssh action_help: Allow the user to uses ssh
api: POST /users/ssh/enable api: POST /users/ssh/enable
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username of the user help: Username of the user
@ -237,8 +218,6 @@ user:
disallow: disallow:
action_help: Disallow the user to uses ssh action_help: Disallow the user to uses ssh
api: POST /users/ssh/disable api: POST /users/ssh/disable
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username of the user help: Username of the user
@ -249,8 +228,6 @@ user:
list-keys: list-keys:
action_help: Show user's authorized ssh keys action_help: Show user's authorized ssh keys
api: GET /users/ssh/keys api: GET /users/ssh/keys
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username of the user help: Username of the user
@ -261,8 +238,6 @@ user:
add-key: add-key:
action_help: Add a new authorized ssh key for this user action_help: Add a new authorized ssh key for this user
api: POST /users/ssh/key api: POST /users/ssh/key
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username of the user help: Username of the user
@ -278,8 +253,6 @@ user:
remove-key: remove-key:
action_help: Remove an authorized ssh key for this user action_help: Remove an authorized ssh key for this user
api: DELETE /users/ssh/key api: DELETE /users/ssh/key
configuration:
authenticate: all
arguments: arguments:
username: username:
help: Username of the user help: Username of the user
@ -300,16 +273,11 @@ domain:
list: list:
action_help: List domains action_help: List domains
api: GET /domains api: GET /domains
configuration:
authenticate: all
authenticator: ldap-anonymous
### domain_add() ### domain_add()
add: add:
action_help: Create a custom domain action_help: Create a custom domain
api: POST /domains api: POST /domains
configuration:
authenticate: all
arguments: arguments:
domain: domain:
help: Domain name to add help: Domain name to add
@ -326,8 +294,6 @@ domain:
remove: remove:
action_help: Delete domains action_help: Delete domains
api: DELETE /domains/<domain> api: DELETE /domains/<domain>
configuration:
authenticate: all
arguments: arguments:
domain: domain:
help: Domain to delete help: Domain to delete
@ -338,9 +304,6 @@ domain:
dns-conf: dns-conf:
action_help: Generate DNS configuration for a domain action_help: Generate DNS configuration for a domain
api: GET /domains/<domain>/dns api: GET /domains/<domain>/dns
configuration:
authenticate:
- api
arguments: arguments:
domain: domain:
help: Target domain help: Target domain
@ -356,9 +319,6 @@ domain:
cert-status: cert-status:
action_help: List status of current certificates (all by default). action_help: List status of current certificates (all by default).
api: GET /domains/cert-status/<domain_list> api: GET /domains/cert-status/<domain_list>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
domain_list: domain_list:
help: Domains to check help: Domains to check
@ -371,9 +331,6 @@ domain:
cert-install: cert-install:
action_help: Install Let's Encrypt certificates for given domains (all by default). action_help: Install Let's Encrypt certificates for given domains (all by default).
api: POST /domains/cert-install/<domain_list> api: POST /domains/cert-install/<domain_list>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
domain_list: domain_list:
help: Domains for which to install the certificates help: Domains for which to install the certificates
@ -395,9 +352,6 @@ domain:
cert-renew: cert-renew:
action_help: Renew the Let's Encrypt certificates for given domains (all by default). action_help: Renew the Let's Encrypt certificates for given domains (all by default).
api: POST /domains/cert-renew/<domain_list> api: POST /domains/cert-renew/<domain_list>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
domain_list: domain_list:
help: Domains for which to renew the certificates help: Domains for which to renew the certificates
@ -419,9 +373,6 @@ domain:
url-available: url-available:
action_help: Check availability of a web path action_help: Check availability of a web path
api: GET /domain/urlavailable api: GET /domain/urlavailable
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
domain: domain:
help: The domain for the web path (e.g. your.domain.tld) help: The domain for the web path (e.g. your.domain.tld)
@ -542,9 +493,6 @@ app:
install: install:
action_help: Install apps action_help: Install apps
api: POST /apps api: POST /apps
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: Name, local path or git URL of the app to install help: Name, local path or git URL of the app to install
@ -567,9 +515,6 @@ app:
remove: remove:
action_help: Remove app action_help: Remove app
api: DELETE /apps/<app> api: DELETE /apps/<app>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App(s) to delete help: App(s) to delete
@ -578,9 +523,6 @@ app:
upgrade: upgrade:
action_help: Upgrade app action_help: Upgrade app
api: PUT /upgrade/apps api: PUT /upgrade/apps
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App(s) to upgrade (default all) help: App(s) to upgrade (default all)
@ -596,9 +538,6 @@ app:
change-url: change-url:
action_help: Change app's URL action_help: Change app's URL
api: PUT /apps/<app>/changeurl api: PUT /apps/<app>/changeurl
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: Target app instance name help: Target app instance name
@ -651,9 +590,6 @@ app:
action_help: Check availability of a web path action_help: Check availability of a web path
api: GET /tools/checkurl api: GET /tools/checkurl
deprecated: True deprecated: True
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
url: url:
help: Url to check help: Url to check
@ -665,9 +601,6 @@ app:
register-url: register-url:
action_help: Book/register a web path for a given app action_help: Book/register a web path for a given app
api: PUT /tools/registerurl api: PUT /tools/registerurl
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App which will use the web path help: App which will use the web path
@ -707,9 +640,6 @@ app:
makedefault: makedefault:
action_help: Redirect domain root to an app action_help: Redirect domain root to an app
api: PUT /apps/<app>/default api: PUT /apps/<app>/default
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App name to put on domain root help: App name to put on domain root
@ -721,17 +651,11 @@ app:
ssowatconf: ssowatconf:
action_help: Regenerate SSOwat configuration file action_help: Regenerate SSOwat configuration file
api: PUT /ssowatconf api: PUT /ssowatconf
configuration:
authenticate: all
authenticator: ldap-anonymous
### app_change_label() ### app_change_label()
change-label: change-label:
action_help: Change app label action_help: Change app label
api: PUT /apps/<app>/label api: PUT /apps/<app>/label
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
app: app:
help: App ID help: App ID
@ -742,9 +666,6 @@ app:
addaccess: addaccess:
action_help: Grant access right to users (everyone by default) action_help: Grant access right to users (everyone by default)
api: PUT /access api: PUT /access
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"
@ -756,9 +677,6 @@ app:
removeaccess: removeaccess:
action_help: Revoke access right to users (everyone by default) action_help: Revoke access right to users (everyone by default)
api: DELETE /access api: DELETE /access
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"
@ -770,9 +688,6 @@ app:
clearaccess: clearaccess:
action_help: Reset access rights for the app action_help: Reset access rights for the app
api: POST /access api: POST /access
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
apps: apps:
nargs: "+" nargs: "+"
@ -870,9 +785,6 @@ backup:
restore: restore:
action_help: Restore from a local backup archive. If neither --apps or --system are given, this will restore all apps and all system parts in the archive. If only --apps if given, this will only restore apps and no system parts. Similarly, if only --system is given, this will only restore system parts and no apps. action_help: Restore from a local backup archive. If neither --apps or --system are given, this will restore all apps and all system parts in the archive. If only --apps if given, this will only restore apps and no system parts. Similarly, if only --system is given, this will only restore system parts and no apps.
api: POST /backup/restore/<name> api: POST /backup/restore/<name>
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
name: name:
help: Name of the local backup archive help: Name of the local backup archive
@ -1481,8 +1393,6 @@ tools:
adminpw: adminpw:
action_help: Change password of admin and root users action_help: Change password of admin and root users
api: PUT /adminpw api: PUT /adminpw
configuration:
authenticate: all
arguments: arguments:
-n: -n:
full: --new-password full: --new-password
@ -1498,8 +1408,6 @@ tools:
api: api:
- GET /domains/main - GET /domains/main
- PUT /domains/main - PUT /domains/main
configuration:
authenticate: all
arguments: arguments:
-n: -n:
full: --new-domain full: --new-domain
@ -1552,9 +1460,6 @@ tools:
upgrade: upgrade:
action_help: YunoHost upgrade action_help: YunoHost upgrade
api: PUT /upgrade api: PUT /upgrade
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
--apps: --apps:
help: List of apps to upgrade (all by default) help: List of apps to upgrade (all by default)
@ -1567,9 +1472,6 @@ tools:
diagnosis: diagnosis:
action_help: YunoHost diagnosis action_help: YunoHost diagnosis
api: GET /diagnosis api: GET /diagnosis
configuration:
authenticate: all
authenticator: ldap-anonymous
arguments: arguments:
-p: -p:
full: --private full: --private
@ -1588,8 +1490,6 @@ tools:
### tools_shell() ### tools_shell()
shell: shell:
configuration:
authenticate: all
action_help: Launch a development shell action_help: Launch a development shell
arguments: arguments:
-c: -c:

View file

@ -81,6 +81,7 @@ checkpoint 512 30
# These access lines apply to database #1 only # These access lines apply to database #1 only
access to attrs=userPassword,shadowLastChange access to attrs=userPassword,shadowLastChange
by dn="cn=admin,dc=yunohost,dc=org" write by dn="cn=admin,dc=yunohost,dc=org" write
by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
by anonymous auth by anonymous auth
by self write by self write
by * none by * none
@ -90,6 +91,7 @@ access to attrs=userPassword,shadowLastChange
# Others should be able to see it. # Others should be able to see it.
access to attrs=cn,gecos,givenName,mail,maildrop,displayName,sn access to attrs=cn,gecos,givenName,mail,maildrop,displayName,sn
by dn="cn=admin,dc=yunohost,dc=org" write by dn="cn=admin,dc=yunohost,dc=org" write
by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
by self write by self write
by * read by * read
@ -108,5 +110,6 @@ access to dn.base="" by * read
# can read everything. # can read everything.
access to * access to *
by dn="cn=admin,dc=yunohost,dc=org" write by dn="cn=admin,dc=yunohost,dc=org" write
by dn.exact="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth" write
by group/groupOfNames/Member="cn=admin,ou=groups,dc=yunohost,dc=org" write by group/groupOfNames/Member="cn=admin,ou=groups,dc=yunohost,dc=org" write
by * read by * read

View file

@ -38,12 +38,12 @@ from collections import OrderedDict
from datetime import datetime from datetime import datetime
from moulinette import msignals, m18n, msettings from moulinette import msignals, m18n, msettings
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.filesystem import read_json from moulinette.utils.filesystem import read_json
from yunohost.service import service_log, service_status, _run_service_command from yunohost.service import service_log, service_status, _run_service_command
from yunohost.utils import packages from yunohost.utils import packages
from yunohost.utils.error import YunohostError
from yunohost.log import is_unit_operation, OperationLogger from yunohost.log import is_unit_operation, OperationLogger
logger = getActionLogger('yunohost.app') logger = getActionLogger('yunohost.app')
@ -437,7 +437,7 @@ def app_map(app=None, raw=False, user=None):
@is_unit_operation() @is_unit_operation()
def app_change_url(operation_logger, auth, app, domain, path): def app_change_url(operation_logger, app, domain, path):
""" """
Modify the URL at which an application is installed. Modify the URL at which an application is installed.
@ -468,7 +468,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
raise YunohostError("app_change_url_identical_domains", domain=domain, path=path) raise YunohostError("app_change_url_identical_domains", domain=domain, path=path)
# Check the url is available # Check the url is available
conflicts = _get_conflicting_apps(auth, domain, path, ignore_app=app) conflicts = _get_conflicting_apps(domain, path, ignore_app=app)
if conflicts: if conflicts:
apps = [] apps = []
for path, app_id, app_label in conflicts: for path, app_id, app_label in conflicts:
@ -484,7 +484,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
# Retrieve arguments list for change_url script # Retrieve arguments list for change_url script
# TODO: Allow to specify arguments # TODO: Allow to specify arguments
args_odict = _parse_args_from_manifest(manifest, 'change_url', auth=auth) args_odict = _parse_args_from_manifest(manifest, 'change_url')
args_list = args_odict.values() args_list = args_odict.values()
args_list.append(app) args_list.append(app)
@ -538,7 +538,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
app_setting(app, 'domain', value=domain) app_setting(app, 'domain', value=domain)
app_setting(app, 'path', value=path) app_setting(app, 'path', value=path)
app_ssowatconf(auth) app_ssowatconf()
# avoid common mistakes # avoid common mistakes
if _run_service_command("reload", "nginx") == False: if _run_service_command("reload", "nginx") == False:
@ -557,7 +557,7 @@ def app_change_url(operation_logger, auth, app, domain, path):
hook_callback('post_app_change_url', args=args_list, env=env_dict) hook_callback('post_app_change_url', args=args_list, env=env_dict)
def app_upgrade(auth, app=[], url=None, file=None): def app_upgrade(app=[], url=None, file=None):
""" """
Upgrade app Upgrade app
@ -633,7 +633,7 @@ def app_upgrade(auth, app=[], url=None, file=None):
# Retrieve arguments list for upgrade script # Retrieve arguments list for upgrade script
# TODO: Allow to specify arguments # TODO: Allow to specify arguments
args_odict = _parse_args_from_manifest(manifest, 'upgrade', auth=auth) args_odict = _parse_args_from_manifest(manifest, 'upgrade')
args_list = args_odict.values() args_list = args_odict.values()
args_list.append(app_instance_name) args_list.append(app_instance_name)
@ -693,13 +693,13 @@ def app_upgrade(auth, app=[], url=None, file=None):
if not_upgraded_apps: if not_upgraded_apps:
raise YunohostError('app_not_upgraded', apps=', '.join(not_upgraded_apps)) raise YunohostError('app_not_upgraded', apps=', '.join(not_upgraded_apps))
app_ssowatconf(auth) app_ssowatconf()
logger.success(m18n.n('upgrade_complete')) logger.success(m18n.n('upgrade_complete'))
@is_unit_operation() @is_unit_operation()
def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on_failure=False, force=False): def app_install(operation_logger, app, label=None, args=None, no_remove_on_failure=False, force=False):
""" """
Install apps Install apps
@ -791,7 +791,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
# Retrieve arguments list for install script # Retrieve arguments list for install script
args_dict = {} if not args else \ args_dict = {} if not args else \
dict(urlparse.parse_qsl(args, keep_blank_values=True)) dict(urlparse.parse_qsl(args, keep_blank_values=True))
args_odict = _parse_args_from_manifest(manifest, 'install', args=args_dict, auth=auth) args_odict = _parse_args_from_manifest(manifest, 'install', args=args_dict)
args_list = args_odict.values() args_list = args_odict.values()
args_list.append(app_instance_name) args_list.append(app_instance_name)
@ -883,7 +883,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
shutil.rmtree(app_setting_path) shutil.rmtree(app_setting_path)
shutil.rmtree(extracted_app_folder) shutil.rmtree(extracted_app_folder)
app_ssowatconf(auth) app_ssowatconf()
if packages.dpkg_is_broken(): if packages.dpkg_is_broken():
logger.error(m18n.n("this_action_broke_dpkg")) logger.error(m18n.n("this_action_broke_dpkg"))
@ -910,7 +910,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
os.system('chown -R root: %s' % app_setting_path) os.system('chown -R root: %s' % app_setting_path)
os.system('chown -R admin: %s/scripts' % app_setting_path) os.system('chown -R admin: %s/scripts' % app_setting_path)
app_ssowatconf(auth) app_ssowatconf()
logger.success(m18n.n('installation_complete')) logger.success(m18n.n('installation_complete'))
@ -918,7 +918,7 @@ def app_install(operation_logger, auth, app, label=None, args=None, no_remove_on
@is_unit_operation() @is_unit_operation()
def app_remove(operation_logger, auth, app): def app_remove(operation_logger, app):
""" """
Remove app Remove app
@ -970,13 +970,13 @@ def app_remove(operation_logger, auth, app):
shutil.rmtree(app_setting_path) shutil.rmtree(app_setting_path)
shutil.rmtree('/tmp/yunohost_remove') shutil.rmtree('/tmp/yunohost_remove')
hook_remove(app) hook_remove(app)
app_ssowatconf(auth) app_ssowatconf()
if packages.dpkg_is_broken(): if packages.dpkg_is_broken():
raise YunohostError("this_action_broke_dpkg") raise YunohostError("this_action_broke_dpkg")
def app_addaccess(auth, apps, users=[]): def app_addaccess(apps, users=[]):
""" """
Grant access right to users (everyone by default) Grant access right to users (everyone by default)
@ -991,7 +991,7 @@ def app_addaccess(auth, apps, users=[]):
result = {} result = {}
if not users: if not users:
users = user_list(auth)['users'].keys() users = user_list()['users'].keys()
elif not isinstance(users, list): elif not isinstance(users, list):
users = [users, ] users = [users, ]
if not isinstance(apps, list): if not isinstance(apps, list):
@ -1021,7 +1021,7 @@ def app_addaccess(auth, apps, users=[]):
for allowed_user in users: for allowed_user in users:
if allowed_user not in allowed_users: if allowed_user not in allowed_users:
try: try:
user_info(auth, allowed_user) user_info(allowed_user)
except YunohostError: except YunohostError:
logger.warning(m18n.n('user_unknown', user=allowed_user)) logger.warning(m18n.n('user_unknown', user=allowed_user))
continue continue
@ -1037,12 +1037,12 @@ def app_addaccess(auth, apps, users=[]):
result[app] = allowed_users result[app] = allowed_users
app_ssowatconf(auth) app_ssowatconf()
return {'allowed_users': result} return {'allowed_users': result}
def app_removeaccess(auth, apps, users=[]): def app_removeaccess(apps, users=[]):
""" """
Revoke access right to users (everyone by default) Revoke access right to users (everyone by default)
@ -1084,7 +1084,7 @@ def app_removeaccess(auth, apps, users=[]):
if allowed_user not in users: if allowed_user not in users:
allowed_users.add(allowed_user) allowed_users.add(allowed_user)
else: else:
for allowed_user in user_list(auth)['users'].keys(): for allowed_user in user_list()['users'].keys():
if allowed_user not in users: if allowed_user not in users:
allowed_users.add(allowed_user) allowed_users.add(allowed_user)
@ -1098,12 +1098,12 @@ def app_removeaccess(auth, apps, users=[]):
operation_logger.success() operation_logger.success()
app_ssowatconf(auth) app_ssowatconf()
return {'allowed_users': result} return {'allowed_users': result}
def app_clearaccess(auth, apps): def app_clearaccess(apps):
""" """
Reset access rights for the app Reset access rights for the app
@ -1136,7 +1136,7 @@ def app_clearaccess(auth, apps):
operation_logger.success() operation_logger.success()
app_ssowatconf(auth) app_ssowatconf()
def app_debug(app): def app_debug(app):
@ -1163,7 +1163,7 @@ def app_debug(app):
@is_unit_operation() @is_unit_operation()
def app_makedefault(operation_logger, auth, app, domain=None): def app_makedefault(operation_logger, app, domain=None):
""" """
Redirect domain root to an app Redirect domain root to an app
@ -1181,7 +1181,7 @@ def app_makedefault(operation_logger, auth, app, domain=None):
if domain is None: if domain is None:
domain = app_domain domain = app_domain
operation_logger.related_to.append(('domain', domain)) operation_logger.related_to.append(('domain', domain))
elif domain not in domain_list(auth)['domains']: elif domain not in domain_list()['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
operation_logger.start() operation_logger.start()
@ -1260,7 +1260,7 @@ def app_checkport(port):
raise YunohostError('port_unavailable', port=int(port)) raise YunohostError('port_unavailable', port=int(port))
def app_register_url(auth, app, domain, path): def app_register_url(app, domain, path):
""" """
Book/register a web path for a given app Book/register a web path for a given app
@ -1286,7 +1286,7 @@ def app_register_url(auth, app, domain, path):
raise YunohostError('app_already_installed_cant_change_url') raise YunohostError('app_already_installed_cant_change_url')
# Check the url is available # Check the url is available
conflicts = _get_conflicting_apps(auth, domain, path) conflicts = _get_conflicting_apps(domain, path)
if conflicts: if conflicts:
apps = [] apps = []
for path, app_id, app_label in conflicts: for path, app_id, app_label in conflicts:
@ -1303,7 +1303,7 @@ def app_register_url(auth, app, domain, path):
app_setting(app, 'path', value=path) app_setting(app, 'path', value=path)
def app_checkurl(auth, url, app=None): def app_checkurl(url, app=None):
""" """
Check availability of a web path Check availability of a web path
@ -1333,7 +1333,7 @@ def app_checkurl(auth, url, app=None):
apps_map = app_map(raw=True) apps_map = app_map(raw=True)
if domain not in domain_list(auth)['domains']: if domain not in domain_list()['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
if domain in apps_map: if domain in apps_map:
@ -1390,7 +1390,7 @@ def app_initdb(user, password=None, db=None, sql=None):
logger.success(m18n.n('mysql_db_initialized')) logger.success(m18n.n('mysql_db_initialized'))
def app_ssowatconf(auth): def app_ssowatconf():
""" """
Regenerate SSOwat configuration file Regenerate SSOwat configuration file
@ -1400,7 +1400,7 @@ def app_ssowatconf(auth):
from yunohost.user import user_list from yunohost.user import user_list
main_domain = _get_maindomain() main_domain = _get_maindomain()
domains = domain_list(auth)['domains'] domains = domain_list()['domains']
skipped_urls = [] skipped_urls = []
skipped_regex = [] skipped_regex = []
@ -1477,7 +1477,7 @@ def app_ssowatconf(auth):
'redirected_urls': redirected_urls, 'redirected_urls': redirected_urls,
'redirected_regex': redirected_regex, 'redirected_regex': redirected_regex,
'users': {username: app_map(user=username) 'users': {username: app_map(user=username)
for username in user_list(auth)['users'].keys()}, for username in user_list()['users'].keys()},
} }
with open('/etc/ssowat/conf.json', 'w+') as f: with open('/etc/ssowat/conf.json', 'w+') as f:
@ -1486,14 +1486,14 @@ def app_ssowatconf(auth):
logger.success(m18n.n('ssowat_conf_generated')) logger.success(m18n.n('ssowat_conf_generated'))
def app_change_label(auth, app, new_label): def app_change_label(app, new_label):
installed = _is_installed(app) installed = _is_installed(app)
if not installed: if not installed:
raise YunohostError('app_not_installed', app=app) raise YunohostError('app_not_installed', app=app)
app_setting(app, "label", value=new_label) app_setting(app, "label", value=new_label)
app_ssowatconf(auth) app_ssowatconf()
# actions todo list: # actions todo list:
@ -2139,7 +2139,7 @@ def _check_manifest_requirements(manifest, app_instance_name):
spec=spec, app=app_instance_name) spec=spec, app=app_instance_name)
def _parse_args_from_manifest(manifest, action, args={}, auth=None): def _parse_args_from_manifest(manifest, action, args={}):
"""Parse arguments needed for an action from the manifest """Parse arguments needed for an action from the manifest
Retrieve specified arguments for the action from the manifest, and parse Retrieve specified arguments for the action from the manifest, and parse
@ -2158,10 +2158,10 @@ def _parse_args_from_manifest(manifest, action, args={}, auth=None):
return OrderedDict() return OrderedDict()
action_args = manifest['arguments'][action] action_args = manifest['arguments'][action]
return _parse_action_args_in_yunohost_format(args, action_args, auth) return _parse_action_args_in_yunohost_format(args, action_args)
def _parse_args_for_action(action, args={}, auth=None): def _parse_args_for_action(action, args={}):
"""Parse arguments needed for an action from the actions list """Parse arguments needed for an action from the actions list
Retrieve specified arguments for the action from the manifest, and parse Retrieve specified arguments for the action from the manifest, and parse
@ -2182,10 +2182,10 @@ def _parse_args_for_action(action, args={}, auth=None):
action_args = action['arguments'] action_args = action['arguments']
return _parse_action_args_in_yunohost_format(args, action_args, auth) return _parse_action_args_in_yunohost_format(args, action_args)
def _parse_action_args_in_yunohost_format(args, action_args, auth=None): def _parse_action_args_in_yunohost_format(args, action_args):
"""Parse arguments store in either manifest.json or actions.json """Parse arguments store in either manifest.json or actions.json
""" """
from yunohost.domain import (domain_list, _get_maindomain, from yunohost.domain import (domain_list, _get_maindomain,
@ -2238,12 +2238,12 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
arg_default = _get_maindomain() arg_default = _get_maindomain()
ask_string += ' (default: {0})'.format(arg_default) ask_string += ' (default: {0})'.format(arg_default)
msignals.display(m18n.n('domains_available')) msignals.display(m18n.n('domains_available'))
for domain in domain_list(auth)['domains']: for domain in domain_list()['domains']:
msignals.display("- {}".format(domain)) msignals.display("- {}".format(domain))
elif arg_type == 'user': elif arg_type == 'user':
msignals.display(m18n.n('users_available')) msignals.display(m18n.n('users_available'))
for user in user_list(auth)['users'].keys(): for user in user_list()['users'].keys():
msignals.display("- {}".format(user)) msignals.display("- {}".format(user))
elif arg_type == 'password': elif arg_type == 'password':
@ -2279,11 +2279,11 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
# Validate argument type # Validate argument type
if arg_type == 'domain': if arg_type == 'domain':
if arg_value not in domain_list(auth)['domains']: if arg_value not in domain_list()['domains']:
raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('domain_unknown')) raise YunohostError('app_argument_invalid', name=arg_name, error=m18n.n('domain_unknown'))
elif arg_type == 'user': elif arg_type == 'user':
try: try:
user_info(auth, arg_value) user_info(arg_value)
except YunohostError as e: except YunohostError as e:
raise YunohostError('app_argument_invalid', name=arg_name, error=e) raise YunohostError('app_argument_invalid', name=arg_name, error=e)
elif arg_type == 'app': elif arg_type == 'app':
@ -2324,7 +2324,7 @@ def _parse_action_args_in_yunohost_format(args, action_args, auth=None):
domain, path = _normalize_domain_path(domain, path) domain, path = _normalize_domain_path(domain, path)
# Check the url is available # Check the url is available
conflicts = _get_conflicting_apps(auth, domain, path) conflicts = _get_conflicting_apps(domain, path)
if conflicts: if conflicts:
apps = [] apps = []
for path, app_id, app_label in conflicts: for path, app_id, app_label in conflicts:

View file

@ -2090,7 +2090,7 @@ def backup_create(name=None, description=None, methods=[],
} }
def backup_restore(auth, name, system=[], apps=[], force=False): def backup_restore(name, system=[], apps=[], force=False):
""" """
Restore from a local backup archive Restore from a local backup archive

View file

@ -86,7 +86,7 @@ DNS_RESOLVERS = [
# #
def certificate_status(auth, domain_list, full=False): def certificate_status(domain_list, full=False):
""" """
Print the status of certificate for given domains (all by default) Print the status of certificate for given domains (all by default)
@ -99,10 +99,10 @@ def certificate_status(auth, domain_list, full=False):
# If no domains given, consider all yunohost domains # If no domains given, consider all yunohost domains
if domain_list == []: if domain_list == []:
domain_list = yunohost.domain.domain_list(auth)['domains'] domain_list = yunohost.domain.domain_list()['domains']
# Else, validate that yunohost knows the domains given # Else, validate that yunohost knows the domains given
else: else:
yunohost_domains_list = yunohost.domain.domain_list(auth)['domains'] yunohost_domains_list = yunohost.domain.domain_list()['domains']
for domain in domain_list: for domain in domain_list:
# Is it in Yunohost domain list? # Is it in Yunohost domain list?
if domain not in yunohost_domains_list: if domain not in yunohost_domains_list:
@ -126,7 +126,7 @@ def certificate_status(auth, domain_list, full=False):
return {"certificates": certificates} return {"certificates": certificates}
def certificate_install(auth, domain_list, force=False, no_checks=False, self_signed=False, staging=False): def certificate_install(domain_list, force=False, no_checks=False, self_signed=False, staging=False):
""" """
Install a Let's Encrypt certificate for given domains (all by default) Install a Let's Encrypt certificate for given domains (all by default)
@ -142,7 +142,7 @@ def certificate_install(auth, domain_list, force=False, no_checks=False, self_si
_certificate_install_selfsigned(domain_list, force) _certificate_install_selfsigned(domain_list, force)
else: else:
_certificate_install_letsencrypt( _certificate_install_letsencrypt(
auth, domain_list, force, no_checks, staging) domain_list, force, no_checks, staging)
def _certificate_install_selfsigned(domain_list, force=False): def _certificate_install_selfsigned(domain_list, force=False):
@ -237,7 +237,7 @@ def _certificate_install_selfsigned(domain_list, force=False):
operation_logger.error(msg) operation_logger.error(msg)
def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=False, staging=False): def _certificate_install_letsencrypt(domain_list, force=False, no_checks=False, staging=False):
import yunohost.domain import yunohost.domain
if not os.path.exists(ACCOUNT_KEY_FILE): if not os.path.exists(ACCOUNT_KEY_FILE):
@ -246,7 +246,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
# If no domains given, consider all yunohost domains with self-signed # If no domains given, consider all yunohost domains with self-signed
# certificates # certificates
if domain_list == []: if domain_list == []:
for domain in yunohost.domain.domain_list(auth)['domains']: for domain in yunohost.domain.domain_list()['domains']:
status = _get_status(domain) status = _get_status(domain)
if status["CA_type"]["code"] != "self-signed": if status["CA_type"]["code"] != "self-signed":
@ -257,7 +257,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
# Else, validate that yunohost knows the domains given # Else, validate that yunohost knows the domains given
else: else:
for domain in domain_list: for domain in domain_list:
yunohost_domains_list = yunohost.domain.domain_list(auth)['domains'] yunohost_domains_list = yunohost.domain.domain_list()['domains']
if domain not in yunohost_domains_list: if domain not in yunohost_domains_list:
raise YunohostError('certmanager_domain_unknown', domain=domain) raise YunohostError('certmanager_domain_unknown', domain=domain)
@ -285,7 +285,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
operation_logger.start() operation_logger.start()
_configure_for_acme_challenge(auth, domain) _configure_for_acme_challenge(domain)
_fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks) _fetch_and_enable_new_certificate(domain, staging, no_checks=no_checks)
_install_cron(no_checks=no_checks) _install_cron(no_checks=no_checks)
@ -300,7 +300,7 @@ def _certificate_install_letsencrypt(auth, domain_list, force=False, no_checks=F
operation_logger.error(msg) operation_logger.error(msg)
def certificate_renew(auth, domain_list, force=False, no_checks=False, email=False, staging=False): def certificate_renew(domain_list, force=False, no_checks=False, email=False, staging=False):
""" """
Renew Let's Encrypt certificate for given domains (all by default) Renew Let's Encrypt certificate for given domains (all by default)
@ -317,7 +317,7 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal
# If no domains given, consider all yunohost domains with Let's Encrypt # If no domains given, consider all yunohost domains with Let's Encrypt
# certificates # certificates
if domain_list == []: if domain_list == []:
for domain in yunohost.domain.domain_list(auth)['domains']: for domain in yunohost.domain.domain_list()['domains']:
# Does it have a Let's Encrypt cert? # Does it have a Let's Encrypt cert?
status = _get_status(domain) status = _get_status(domain)
@ -344,7 +344,7 @@ def certificate_renew(auth, domain_list, force=False, no_checks=False, email=Fal
for domain in domain_list: for domain in domain_list:
# Is it in Yunohost dmomain list? # Is it in Yunohost dmomain list?
if domain not in yunohost.domain.domain_list(auth)['domains']: if domain not in yunohost.domain.domain_list()['domains']:
raise YunohostError('certmanager_domain_unknown', domain=domain) raise YunohostError('certmanager_domain_unknown', domain=domain)
status = _get_status(domain) status = _get_status(domain)
@ -468,7 +468,7 @@ Subject: %s
smtp.quit() smtp.quit()
def _configure_for_acme_challenge(auth, domain): def _configure_for_acme_challenge(domain):
nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain nginx_conf_folder = "/etc/nginx/conf.d/%s.d" % domain
nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder nginx_conf_file = "%s/000-acmechallenge.conf" % nginx_conf_folder
@ -511,7 +511,7 @@ location ^~ '/.well-known/acme-challenge/'
# any clean function already implemented in yunohost to do this though) # any clean function already implemented in yunohost to do this though)
_run_service_command("reload", "nginx") _run_service_command("reload", "nginx")
app_ssowatconf(auth) app_ssowatconf()
def _check_acme_challenge_configuration(domain): def _check_acme_challenge_configuration(domain):

View file

@ -42,7 +42,7 @@ from yunohost.hook import hook_callback
logger = getActionLogger('yunohost.domain') logger = getActionLogger('yunohost.domain')
def domain_list(auth): def domain_list():
""" """
List domains List domains
@ -52,10 +52,12 @@ def domain_list(auth):
limit -- Maximum number of domain fetched limit -- Maximum number of domain fetched
""" """
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
result = ldap.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain'])
result_list = [] result_list = []
result = auth.search('ou=domains,dc=yunohost,dc=org', 'virtualdomain=*', ['virtualdomain'])
for domain in result: for domain in result:
result_list.append(domain['virtualdomain'][0]) result_list.append(domain['virtualdomain'][0])
@ -63,7 +65,7 @@ def domain_list(auth):
@is_unit_operation() @is_unit_operation()
def domain_add(operation_logger, auth, domain, dyndns=False): def domain_add(operation_logger, domain, dyndns=False):
""" """
Create a custom domain Create a custom domain
@ -74,9 +76,12 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
""" """
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.app import app_ssowatconf from yunohost.app import app_ssowatconf
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
try: try:
auth.validate_uniqueness({'virtualdomain': domain}) ldap.validate_uniqueness({'virtualdomain': domain})
except MoulinetteError: except MoulinetteError:
raise YunohostError('domain_exists') raise YunohostError('domain_exists')
@ -107,18 +112,18 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
'virtualdomain': domain, 'virtualdomain': domain,
} }
if not auth.add('virtualdomain=%s,ou=domains' % domain, attr_dict): if not ldap.add('virtualdomain=%s,ou=domains' % domain, attr_dict):
raise YunohostError('domain_creation_failed') raise YunohostError('domain_creation_failed')
# Don't regen these conf if we're still in postinstall # Don't regen these conf if we're still in postinstall
if os.path.exists('/etc/yunohost/installed'): if os.path.exists('/etc/yunohost/installed'):
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd']) regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix', 'rspamd'])
app_ssowatconf(auth) app_ssowatconf()
except Exception: except Exception:
# Force domain removal silently # Force domain removal silently
try: try:
domain_remove(auth, domain, True) domain_remove(domain, True)
except: except:
pass pass
raise raise
@ -129,7 +134,7 @@ def domain_add(operation_logger, auth, domain, dyndns=False):
@is_unit_operation() @is_unit_operation()
def domain_remove(operation_logger, auth, domain, force=False): def domain_remove(operation_logger, domain, force=False):
""" """
Delete domains Delete domains
@ -140,8 +145,9 @@ def domain_remove(operation_logger, auth, domain, force=False):
""" """
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.app import app_ssowatconf from yunohost.app import app_ssowatconf
from yunohost.utils.ldap import _get_ldap_interface
if not force and domain not in domain_list(auth)['domains']: if not force and domain not in domain_list()['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
# Check domain is not the main domain # Check domain is not the main domain
@ -160,13 +166,14 @@ def domain_remove(operation_logger, auth, domain, force=False):
raise YunohostError('domain_uninstall_app_first') raise YunohostError('domain_uninstall_app_first')
operation_logger.start() operation_logger.start()
if auth.remove('virtualdomain=' + domain + ',ou=domains') or force: ldap = _get_ldap_interface()
if ldap.remove('virtualdomain=' + domain + ',ou=domains') or force:
os.system('rm -rf /etc/yunohost/certs/%s' % domain) os.system('rm -rf /etc/yunohost/certs/%s' % domain)
else: else:
raise YunohostError('domain_deletion_failed') raise YunohostError('domain_deletion_failed')
regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix']) regen_conf(names=['nginx', 'metronome', 'dnsmasq', 'postfix'])
app_ssowatconf(auth) app_ssowatconf()
hook_callback('post_domain_remove', args=[domain]) hook_callback('post_domain_remove', args=[domain])
@ -222,19 +229,19 @@ def domain_dns_conf(domain, ttl=None):
return result return result
def domain_cert_status(auth, domain_list, full=False): def domain_cert_status(domain_list, full=False):
return yunohost.certificate.certificate_status(auth, domain_list, full) return yunohost.certificate.certificate_status(domain_list, full)
def domain_cert_install(auth, domain_list, force=False, no_checks=False, self_signed=False, staging=False): def domain_cert_install(domain_list, force=False, no_checks=False, self_signed=False, staging=False):
return yunohost.certificate.certificate_install(auth, domain_list, force, no_checks, self_signed, staging) return yunohost.certificate.certificate_install(domain_list, force, no_checks, self_signed, staging)
def domain_cert_renew(auth, domain_list, force=False, no_checks=False, email=False, staging=False): def domain_cert_renew(domain_list, force=False, no_checks=False, email=False, staging=False):
return yunohost.certificate.certificate_renew(auth, domain_list, force, no_checks, email, staging) return yunohost.certificate.certificate_renew(domain_list, force, no_checks, email, staging)
def _get_conflicting_apps(auth, domain, path, ignore_app=None): def _get_conflicting_apps(domain, path, ignore_app=None):
""" """
Return a list of all conflicting apps with a domain/path (it can be empty) Return a list of all conflicting apps with a domain/path (it can be empty)
@ -247,7 +254,7 @@ def _get_conflicting_apps(auth, domain, path, ignore_app=None):
domain, path = _normalize_domain_path(domain, path) domain, path = _normalize_domain_path(domain, path)
# Abort if domain is unknown # Abort if domain is unknown
if domain not in domain_list(auth)['domains']: if domain not in domain_list()['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
# This import cannot be put on top of file because it would create a # This import cannot be put on top of file because it would create a
@ -274,7 +281,7 @@ def _get_conflicting_apps(auth, domain, path, ignore_app=None):
return conflicts return conflicts
def domain_url_available(auth, domain, path): def domain_url_available(domain, path):
""" """
Check availability of a web path Check availability of a web path
@ -283,7 +290,7 @@ def domain_url_available(auth, domain, path):
path -- The path to check (e.g. /coffee) path -- The path to check (e.g. /coffee)
""" """
return len(_get_conflicting_apps(auth, domain, path)) == 0 return len(_get_conflicting_apps(domain, path)) == 0
def _get_maindomain(): def _get_maindomain():

View file

@ -208,7 +208,7 @@ def log_display(path, number=50, share=False):
def is_unit_operation(entities=['app', 'domain', 'service', 'user'], def is_unit_operation(entities=['app', 'domain', 'service', 'user'],
exclude=['auth', 'password'], operation_key=None): exclude=['password'], operation_key=None):
""" """
Configure quickly a unit operation Configure quickly a unit operation
@ -222,9 +222,8 @@ def is_unit_operation(entities=['app', 'domain', 'service', 'user'],
(argname, entity_type) instead of just put the entity type. (argname, entity_type) instead of just put the entity type.
exclude Remove some arguments from the context. By default, arguments exclude Remove some arguments from the context. By default, arguments
called 'password' and 'auth' are removed. If an argument is an object, you called 'password' are removed. If an argument is an object, you need to
need to exclude it or create manually the unit operation without this exclude it or create manually the unit operation without this decorator.
decorator.
operation_key A key to describe the unit operation log used to create the operation_key A key to describe the unit operation log used to create the
filename and search a translation. Please ensure that this key prefixed by filename and search a translation. Please ensure that this key prefixed by

View file

@ -11,7 +11,7 @@ from moulinette.utils.filesystem import read_file, write_to_file, chown, chmod,
SSHD_CONFIG_PATH = "/etc/ssh/sshd_config" SSHD_CONFIG_PATH = "/etc/ssh/sshd_config"
def user_ssh_allow(auth, username): def user_ssh_allow(username):
""" """
Allow YunoHost user connect as ssh. Allow YunoHost user connect as ssh.
@ -20,17 +20,19 @@ def user_ssh_allow(auth, username):
""" """
# TODO it would be good to support different kind of shells # TODO it would be good to support different kind of shells
if not _get_user_for_ssh(auth, username): if not _get_user_for_ssh(username):
raise YunohostError('user_unknown', user=username) raise YunohostError('user_unknown', user=username)
auth.update('uid=%s,ou=users' % username, {'loginShell': '/bin/bash'}) from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
ldap.update('uid=%s,ou=users' % username, {'loginShell': '/bin/bash'})
# Somehow this is needed otherwise the PAM thing doesn't forget about the # Somehow this is needed otherwise the PAM thing doesn't forget about the
# old loginShell value ? # old loginShell value ?
subprocess.call(['nscd', '-i', 'passwd']) subprocess.call(['nscd', '-i', 'passwd'])
def user_ssh_disallow(auth, username): def user_ssh_disallow(username):
""" """
Disallow YunoHost user connect as ssh. Disallow YunoHost user connect as ssh.
@ -39,18 +41,20 @@ def user_ssh_disallow(auth, username):
""" """
# TODO it would be good to support different kind of shells # TODO it would be good to support different kind of shells
if not _get_user_for_ssh(auth, username): if not _get_user_for_ssh(username):
raise YunohostError('user_unknown', user=username) raise YunohostError('user_unknown', user=username)
auth.update('uid=%s,ou=users' % username, {'loginShell': '/bin/false'}) from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
ldap.update('uid=%s,ou=users' % username, {'loginShell': '/bin/false'})
# Somehow this is needed otherwise the PAM thing doesn't forget about the # Somehow this is needed otherwise the PAM thing doesn't forget about the
# old loginShell value ? # old loginShell value ?
subprocess.call(['nscd', '-i', 'passwd']) subprocess.call(['nscd', '-i', 'passwd'])
def user_ssh_list_keys(auth, username): def user_ssh_list_keys(username):
user = _get_user_for_ssh(auth, username, ["homeDirectory"]) user = _get_user_for_ssh(username, ["homeDirectory"])
if not user: if not user:
raise Exception("User with username '%s' doesn't exists" % username) raise Exception("User with username '%s' doesn't exists" % username)
@ -82,8 +86,8 @@ def user_ssh_list_keys(auth, username):
return {"keys": keys} return {"keys": keys}
def user_ssh_add_key(auth, username, key, comment): def user_ssh_add_key(username, key, comment):
user = _get_user_for_ssh(auth, username, ["homeDirectory", "uid"]) user = _get_user_for_ssh(username, ["homeDirectory", "uid"])
if not user: if not user:
raise Exception("User with username '%s' doesn't exists" % username) raise Exception("User with username '%s' doesn't exists" % username)
@ -116,8 +120,8 @@ def user_ssh_add_key(auth, username, key, comment):
write_to_file(authorized_keys_file, authorized_keys_content) write_to_file(authorized_keys_file, authorized_keys_content)
def user_ssh_remove_key(auth, username, key): def user_ssh_remove_key(username, key):
user = _get_user_for_ssh(auth, username, ["homeDirectory", "uid"]) user = _get_user_for_ssh(username, ["homeDirectory", "uid"])
if not user: if not user:
raise Exception("User with username '%s' doesn't exists" % username) raise Exception("User with username '%s' doesn't exists" % username)
@ -148,8 +152,8 @@ def user_ssh_remove_key(auth, username, key):
# #
def _get_user_for_ssh(auth, username, attrs=None): def _get_user_for_ssh(username, attrs=None):
def ssh_root_login_status(auth): def ssh_root_login_status():
# XXX temporary placed here for when the ssh_root commands are integrated # XXX temporary placed here for when the ssh_root commands are integrated
# extracted from https://github.com/YunoHost/yunohost/pull/345 # extracted from https://github.com/YunoHost/yunohost/pull/345
# XXX should we support all the options? # XXX should we support all the options?
@ -172,7 +176,7 @@ def _get_user_for_ssh(auth, username, attrs=None):
'username': 'root', 'username': 'root',
'fullname': '', 'fullname': '',
'mail': '', 'mail': '',
'ssh_allowed': ssh_root_login_status(auth)["PermitRootLogin"], 'ssh_allowed': ssh_root_login_status()["PermitRootLogin"],
'shell': root_unix.pw_shell, 'shell': root_unix.pw_shell,
'home_path': root_unix.pw_dir, 'home_path': root_unix.pw_dir,
} }
@ -189,7 +193,9 @@ def _get_user_for_ssh(auth, username, attrs=None):
} }
# TODO escape input using https://www.python-ldap.org/doc/html/ldap-filter.html # TODO escape input using https://www.python-ldap.org/doc/html/ldap-filter.html
user = auth.search('ou=users,dc=yunohost,dc=org', from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
user = ldap.search('ou=users,dc=yunohost,dc=org',
'(&(objectclass=person)(uid=%s))' % username, '(&(objectclass=person)(uid=%s))' % username,
attrs) attrs)

View file

@ -1,15 +1,9 @@
import pytest import pytest
from moulinette.core import init_authenticator
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
from yunohost.app import app_install, app_remove from yunohost.app import app_install, app_remove
from yunohost.domain import _get_maindomain, domain_url_available, _normalize_domain_path from yunohost.domain import _get_maindomain, domain_url_available, _normalize_domain_path
# Instantiate LDAP Authenticator
auth_identifier = ('ldap', 'ldap-anonymous')
auth_parameters = {'uri': 'ldap://localhost:389', 'base_dn': 'dc=yunohost,dc=org'}
auth = init_authenticator(auth_identifier, auth_parameters)
# Get main domain # Get main domain
maindomain = _get_maindomain() maindomain = _get_maindomain()
@ -18,7 +12,7 @@ maindomain = _get_maindomain()
def setup_function(function): def setup_function(function):
try: try:
app_remove(auth, "register_url_app") app_remove("register_url_app")
except: except:
pass pass
@ -26,7 +20,7 @@ def setup_function(function):
def teardown_function(function): def teardown_function(function):
try: try:
app_remove(auth, "register_url_app") app_remove("register_url_app")
except: except:
pass pass
@ -41,28 +35,28 @@ def test_normalize_domain_path():
def test_urlavailable(): def test_urlavailable():
# Except the maindomain/macnuggets to be available # Except the maindomain/macnuggets to be available
assert domain_url_available(auth, maindomain, "/macnuggets") assert domain_url_available(maindomain, "/macnuggets")
# We don't know the domain yolo.swag # We don't know the domain yolo.swag
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
assert domain_url_available(auth, "yolo.swag", "/macnuggets") assert domain_url_available("yolo.swag", "/macnuggets")
def test_registerurl(): def test_registerurl():
app_install(auth, "./tests/apps/register_url_app_ynh", app_install("./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True)
assert not domain_url_available(auth, maindomain, "/urlregisterapp") assert not domain_url_available(maindomain, "/urlregisterapp")
# Try installing at same location # Try installing at same location
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install("./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True) args="domain=%s&path=%s" % (maindomain, "/urlregisterapp"), force=True)
def test_registerurl_baddomain(): def test_registerurl_baddomain():
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_install(auth, "./tests/apps/register_url_app_ynh", app_install("./tests/apps/register_url_app_ynh",
args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp"), force=True) args="domain=%s&path=%s" % ("yolo.swag", "/urlregisterapp"), force=True)

View file

@ -1,13 +1,10 @@
import pytest import pytest
import time
import requests
import os import os
import shutil import shutil
import subprocess import subprocess
from mock import ANY from mock import ANY
from moulinette import m18n from moulinette import m18n
from moulinette.core import init_authenticator
from yunohost.app import app_install, app_remove, app_ssowatconf from yunohost.app import app_install, app_remove, app_ssowatconf
from yunohost.app import _is_installed from yunohost.app import _is_installed
from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount from yunohost.backup import backup_create, backup_restore, backup_list, backup_info, backup_delete, _recursive_umount
@ -17,12 +14,6 @@ from yunohost.utils.error import YunohostError
# Get main domain # Get main domain
maindomain = "" maindomain = ""
# Instantiate LDAP Authenticator
AUTH_IDENTIFIER = ('ldap', 'ldap-anonymous')
AUTH_PARAMETERS = {'uri': 'ldap://localhost:389', 'base_dn': 'dc=yunohost,dc=org'}
auth = None
def setup_function(function): def setup_function(function):
global maindomain global maindomain
@ -30,9 +21,6 @@ def setup_function(function):
print "" print ""
global auth
auth = init_authenticator(AUTH_IDENTIFIER, AUTH_PARAMETERS)
assert backup_test_dependencies_are_met() assert backup_test_dependencies_are_met()
clean_tmp_backup_directory() clean_tmp_backup_directory()
@ -72,10 +60,6 @@ def setup_function(function):
def teardown_function(function): def teardown_function(function):
print ""
global auth
auth = init_authenticator(AUTH_IDENTIFIER, AUTH_PARAMETERS)
assert tmp_backup_directory_is_empty() assert tmp_backup_directory_is_empty()
reset_ssowat_conf() reset_ssowat_conf()
@ -146,7 +130,7 @@ def reset_ssowat_conf():
# Make sure we have a ssowat # Make sure we have a ssowat
os.system("mkdir -p /etc/ssowat/") os.system("mkdir -p /etc/ssowat/")
app_ssowatconf(auth) app_ssowatconf()
def delete_all_backups(): def delete_all_backups():
@ -158,18 +142,18 @@ def delete_all_backups():
def uninstall_test_apps_if_needed(): def uninstall_test_apps_if_needed():
if _is_installed("backup_legacy_app"): if _is_installed("backup_legacy_app"):
app_remove(auth, "backup_legacy_app") app_remove("backup_legacy_app")
if _is_installed("backup_recommended_app"): if _is_installed("backup_recommended_app"):
app_remove(auth, "backup_recommended_app") app_remove("backup_recommended_app")
if _is_installed("wordpress"): if _is_installed("wordpress"):
app_remove(auth, "wordpress") app_remove("wordpress")
def install_app(app, path, additionnal_args=""): def install_app(app, path, additionnal_args=""):
app_install(auth, "./tests/apps/%s" % app, app_install("./tests/apps/%s" % app,
args="domain=%s&path=%s%s" % (maindomain, path, args="domain=%s&path=%s%s" % (maindomain, path,
additionnal_args), force=True) additionnal_args), force=True)
@ -249,7 +233,7 @@ def test_backup_and_restore_all_sys():
assert not os.path.exists("/etc/ssowat/conf.json") assert not os.path.exists("/etc/ssowat/conf.json")
# Restore the backup # Restore the backup
backup_restore(auth, name=archives[0], force=True, backup_restore(name=archives[0], force=True,
system=[], apps=None) system=[], apps=None)
# Check ssowat conf is back # Check ssowat conf is back
@ -270,13 +254,13 @@ def test_restore_system_from_Ynh2p4(monkeypatch, mocker):
# Restore system archive from 2.4 # Restore system archive from 2.4
try: try:
backup_restore(auth, name=backup_list()["archives"][1], backup_restore(name=backup_list()["archives"][1],
system=[], system=[],
apps=None, apps=None,
force=True) force=True)
finally: finally:
# Restore system as it was # Restore system as it was
backup_restore(auth, name=backup_list()["archives"][0], backup_restore(name=backup_list()["archives"][0],
system=[], system=[],
apps=None, apps=None,
force=True) force=True)
@ -412,7 +396,7 @@ def test_backup_with_no_compress():
@pytest.mark.with_wordpress_archive_from_2p4 @pytest.mark.with_wordpress_archive_from_2p4
def test_restore_app_wordpress_from_Ynh2p4(): def test_restore_app_wordpress_from_Ynh2p4():
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
@ -430,7 +414,7 @@ def test_restore_app_script_failure_handling(monkeypatch, mocker):
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_app_failed', app='wordpress') m18n.n.assert_any_call('restore_app_failed', app='wordpress')
@ -451,7 +435,7 @@ def test_restore_app_not_enough_free_space(monkeypatch, mocker):
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_not_enough_disk_space', m18n.n.assert_any_call('restore_not_enough_disk_space',
@ -470,7 +454,7 @@ def test_restore_app_not_in_backup(mocker):
mocker.spy(m18n, "n") mocker.spy(m18n, "n")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["yoloswag"]) apps=["yoloswag"])
m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag") m18n.n.assert_any_call('backup_archive_app_not_found', app="yoloswag")
@ -483,14 +467,14 @@ def test_restore_app_already_installed(mocker):
assert not _is_installed("wordpress") assert not _is_installed("wordpress")
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
assert _is_installed("wordpress") assert _is_installed("wordpress")
mocker.spy(m18n, "n") mocker.spy(m18n, "n")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, system=None, name=backup_list()["archives"][0], backup_restore(system=None, name=backup_list()["archives"][0],
apps=["wordpress"]) apps=["wordpress"])
m18n.n.assert_any_call('restore_already_installed_app', app="wordpress") m18n.n.assert_any_call('restore_already_installed_app', app="wordpress")
@ -531,11 +515,11 @@ def _test_backup_and_restore_app(app):
assert app in archives_info["apps"].keys() assert app in archives_info["apps"].keys()
# Uninstall the app # Uninstall the app
app_remove(auth, app) app_remove(app)
assert not app_is_installed(app) assert not app_is_installed(app)
# Restore the app # Restore the app
backup_restore(auth, system=None, name=archives[0], backup_restore(system=None, name=archives[0],
apps=[app]) apps=[app])
assert app_is_installed(app) assert app_is_installed(app)
@ -555,7 +539,7 @@ def test_restore_archive_with_no_json(mocker):
mocker.spy(m18n, "n") mocker.spy(m18n, "n")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
backup_restore(auth, name="badbackup", force=True) backup_restore(name="badbackup", force=True)
m18n.n.assert_any_call('backup_invalid_archive') m18n.n.assert_any_call('backup_invalid_archive')

View file

@ -2,18 +2,11 @@ import pytest
import time import time
import requests import requests
from moulinette.core import init_authenticator
from yunohost.app import app_install, app_change_url, app_remove, app_map from yunohost.app import app_install, app_change_url, app_remove, app_map
from yunohost.domain import _get_maindomain from yunohost.domain import _get_maindomain
from yunohost.utils.error import YunohostError from yunohost.utils.error import YunohostError
# Instantiate LDAP Authenticator
AUTH_IDENTIFIER = ('ldap', 'ldap-anonymous')
AUTH_PARAMETERS = {'uri': 'ldap://localhost:389', 'base_dn': 'dc=yunohost,dc=org'}
auth = init_authenticator(AUTH_IDENTIFIER, AUTH_PARAMETERS)
# Get main domain # Get main domain
maindomain = _get_maindomain() maindomain = _get_maindomain()
@ -23,11 +16,11 @@ def setup_function(function):
def teardown_function(function): def teardown_function(function):
app_remove(auth, "change_url_app") app_remove("change_url_app")
def install_changeurl_app(path): def install_changeurl_app(path):
app_install(auth, "./tests/apps/change_url_app_ynh", app_install("./tests/apps/change_url_app_ynh",
args="domain=%s&path=%s" % (maindomain, path), force=True) args="domain=%s&path=%s" % (maindomain, path), force=True)
@ -46,7 +39,7 @@ def test_appchangeurl():
install_changeurl_app("/changeurl") install_changeurl_app("/changeurl")
check_changeurl_app("/changeurl") check_changeurl_app("/changeurl")
app_change_url(auth, "change_url_app", maindomain, "/newchangeurl") app_change_url("change_url_app", maindomain, "/newchangeurl")
# For some reason the nginx reload can take some time to propagate ...? # For some reason the nginx reload can take some time to propagate ...?
time.sleep(2) time.sleep(2)
@ -59,4 +52,4 @@ def test_appchangeurl_sameurl():
check_changeurl_app("/changeurl") check_changeurl_app("/changeurl")
with pytest.raises(YunohostError): with pytest.raises(YunohostError):
app_change_url(auth, "change_url_app", maindomain, "changeurl") app_change_url("change_url_app", maindomain, "changeurl")

View file

@ -35,8 +35,6 @@ from importlib import import_module
from collections import OrderedDict from collections import OrderedDict
from moulinette import msignals, m18n from moulinette import msignals, m18n
from moulinette.core import init_authenticator
from yunohost.utils.error import YunohostError
from moulinette.utils.log import getActionLogger from moulinette.utils.log import getActionLogger
from moulinette.utils.process import check_output, call_async_output from moulinette.utils.process import check_output, call_async_output
from moulinette.utils.filesystem import read_json, write_to_json from moulinette.utils.filesystem import read_json, write_to_json
@ -49,6 +47,7 @@ from yunohost.regenconf import regen_conf
from yunohost.monitor import monitor_disk, monitor_system from yunohost.monitor import monitor_disk, monitor_system
from yunohost.utils.packages import ynh_packages_version, _dump_sources_list, _list_upgradable_apt_packages from yunohost.utils.packages import ynh_packages_version, _dump_sources_list, _list_upgradable_apt_packages
from yunohost.utils.network import get_public_ip from yunohost.utils.network import get_public_ip
from yunohost.utils.error import YunohostError
from yunohost.log import is_unit_operation, OperationLogger from yunohost.log import is_unit_operation, OperationLogger
# FIXME this is a duplicate from apps.py # FIXME this is a duplicate from apps.py
@ -65,25 +64,21 @@ def tools_ldapinit():
""" """
# Instantiate LDAP Authenticator
auth = init_authenticator(('ldap', 'default'),
{'uri': "ldap://localhost:389",
'base_dn': "dc=yunohost,dc=org",
'user_rdn': "cn=admin"})
auth.authenticate('yunohost')
with open('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') as f: with open('/usr/share/yunohost/yunohost-config/moulinette/ldap_scheme.yml') as f:
ldap_map = yaml.load(f) ldap_map = yaml.load(f)
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
for rdn, attr_dict in ldap_map['parents'].items(): for rdn, attr_dict in ldap_map['parents'].items():
try: try:
auth.add(rdn, attr_dict) ldap.add(rdn, attr_dict)
except Exception as e: except Exception as e:
logger.warn("Error when trying to inject '%s' -> '%s' into ldap: %s" % (rdn, attr_dict, e)) logger.warn("Error when trying to inject '%s' -> '%s' into ldap: %s" % (rdn, attr_dict, e))
for rdn, attr_dict in ldap_map['children'].items(): for rdn, attr_dict in ldap_map['children'].items():
try: try:
auth.add(rdn, attr_dict) ldap.add(rdn, attr_dict)
except Exception as e: except Exception as e:
logger.warn("Error when trying to inject '%s' -> '%s' into ldap: %s" % (rdn, attr_dict, e)) logger.warn("Error when trying to inject '%s' -> '%s' into ldap: %s" % (rdn, attr_dict, e))
@ -99,7 +94,7 @@ def tools_ldapinit():
'userPassword': 'yunohost' 'userPassword': 'yunohost'
} }
auth.update('cn=admin', admin_dict) ldap.update('cn=admin', admin_dict)
# Force nscd to refresh cache to take admin creation into account # Force nscd to refresh cache to take admin creation into account
subprocess.call(['nscd', '-i', 'passwd']) subprocess.call(['nscd', '-i', 'passwd'])
@ -112,10 +107,9 @@ def tools_ldapinit():
raise YunohostError('installation_failed') raise YunohostError('installation_failed')
logger.success(m18n.n('ldap_initialized')) logger.success(m18n.n('ldap_initialized'))
return auth
def tools_adminpw(auth, new_password, check_strength=True): def tools_adminpw(new_password, check_strength=True):
""" """
Change admin password Change admin password
@ -137,8 +131,11 @@ def tools_adminpw(auth, new_password, check_strength=True):
new_hash = _hash_user_password(new_password) new_hash = _hash_user_password(new_password)
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
try: try:
auth.update("cn=admin", {"userPassword": new_hash, }) ldap.update("cn=admin", {"userPassword": new_hash, })
except: except:
logger.exception('unable to change admin password') logger.exception('unable to change admin password')
raise YunohostError('admin_password_change_failed') raise YunohostError('admin_password_change_failed')
@ -162,7 +159,7 @@ def tools_adminpw(auth, new_password, check_strength=True):
@is_unit_operation() @is_unit_operation()
def tools_maindomain(operation_logger, auth, new_domain=None): def tools_maindomain(operation_logger, new_domain=None):
""" """
Check the current main domain, or change it Check the current main domain, or change it
@ -176,7 +173,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
return {'current_main_domain': _get_maindomain()} return {'current_main_domain': _get_maindomain()}
# Check domain exists # Check domain exists
if new_domain not in domain_list(auth)['domains']: if new_domain not in domain_list()['domains']:
raise YunohostError('domain_unknown') raise YunohostError('domain_unknown')
operation_logger.related_to.append(('domain', new_domain)) operation_logger.related_to.append(('domain', new_domain))
@ -205,7 +202,7 @@ def tools_maindomain(operation_logger, auth, new_domain=None):
_set_hostname(new_domain) _set_hostname(new_domain)
# Generate SSOwat configuration file # Generate SSOwat configuration file
app_ssowatconf(auth) app_ssowatconf()
# Regen configurations # Regen configurations
try: try:
@ -332,7 +329,7 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
# Initialize LDAP for YunoHost # Initialize LDAP for YunoHost
# TODO: Improve this part by integrate ldapinit into conf_regen hook # TODO: Improve this part by integrate ldapinit into conf_regen hook
auth = tools_ldapinit() tools_ldapinit()
# Create required folders # Create required folders
folders_to_create = [ folders_to_create = [
@ -406,11 +403,11 @@ def tools_postinstall(operation_logger, domain, password, ignore_dyndns=False,
# New domain config # New domain config
regen_conf(['nsswitch'], force=True) regen_conf(['nsswitch'], force=True)
domain_add(auth, domain, dyndns) domain_add(domain, dyndns)
tools_maindomain(auth, domain) tools_maindomain(domain)
# Change LDAP admin password # Change LDAP admin password
tools_adminpw(auth, password, check_strength=not force_password) tools_adminpw(password, check_strength=not force_password)
# Enable UPnP silently and reload firewall # Enable UPnP silently and reload firewall
firewall_upnp('enable', no_refresh=True) firewall_upnp('enable', no_refresh=True)
@ -544,7 +541,7 @@ def _list_upgradable_apps():
@is_unit_operation() @is_unit_operation()
def tools_upgrade(operation_logger, auth, apps=None, system=False): def tools_upgrade(operation_logger, apps=None, system=False):
""" """
Update apps & package cache, then display changelog Update apps & package cache, then display changelog
@ -583,7 +580,7 @@ def tools_upgrade(operation_logger, auth, apps=None, system=False):
# Actually start the upgrades # Actually start the upgrades
try: try:
app_upgrade(auth, app=apps) app_upgrade(app=apps)
except Exception as e: except Exception as e:
logger.warning('unable to upgrade apps: %s' % str(e)) logger.warning('unable to upgrade apps: %s' % str(e))
logger.error(m18n.n('app_upgrade_some_app_failed')) logger.error(m18n.n('app_upgrade_some_app_failed'))
@ -706,7 +703,7 @@ def tools_upgrade(operation_logger, auth, apps=None, system=False):
operation_logger.success() operation_logger.success()
def tools_diagnosis(auth, private=False): def tools_diagnosis(private=False):
""" """
Return global info about current yunohost instance to help debugging Return global info about current yunohost instance to help debugging
@ -801,7 +798,7 @@ def tools_diagnosis(auth, private=False):
diagnosis['private']['public_ip']['IPv6'] = get_public_ip(6) diagnosis['private']['public_ip']['IPv6'] = get_public_ip(6)
# Domains # Domains
diagnosis['private']['domains'] = domain_list(auth)['domains'] diagnosis['private']['domains'] = domain_list()['domains']
diagnosis['private']['regen_conf'] = regen_conf(with_diff=True, dry_run=True) diagnosis['private']['regen_conf'] = regen_conf(with_diff=True, dry_run=True)
@ -1125,18 +1122,21 @@ def tools_migrations_state():
return read_json(MIGRATIONS_STATE_PATH) return read_json(MIGRATIONS_STATE_PATH)
def tools_shell(auth, command=None): def tools_shell(command=None):
""" """
Launch an (i)python shell in the YunoHost context. Launch an (i)python shell in the YunoHost context.
This is entirely aim for development. This is entirely aim for development.
""" """
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
if command: if command:
exec(command) exec(command)
return return
logger.warn("The \033[1;34mauth\033[0m is available in this context") logger.warn("The \033[1;34mldap\033[0m interface is available in this context")
try: try:
from IPython import embed from IPython import embed
embed() embed()

View file

@ -41,7 +41,7 @@ from yunohost.log import is_unit_operation
logger = getActionLogger('yunohost.user') logger = getActionLogger('yunohost.user')
def user_list(auth, fields=None): def user_list(fields=None):
""" """
List users List users
@ -52,6 +52,8 @@ def user_list(auth, fields=None):
fields -- fields to fetch fields -- fields to fetch
""" """
from yunohost.utils.ldap import _get_ldap_interface
user_attrs = { user_attrs = {
'uid': 'username', 'uid': 'username',
'cn': 'fullname', 'cn': 'fullname',
@ -75,7 +77,8 @@ def user_list(auth, fields=None):
else: else:
attrs = ['uid', 'cn', 'mail', 'mailuserquota', 'loginShell'] attrs = ['uid', 'cn', 'mail', 'mailuserquota', 'loginShell']
result = auth.search('ou=users,dc=yunohost,dc=org', ldap = _get_ldap_interface()
result = ldap.search('ou=users,dc=yunohost,dc=org',
'(&(objectclass=person)(!(uid=root))(!(uid=nobody)))', '(&(objectclass=person)(!(uid=root))(!(uid=nobody)))',
attrs) attrs)
@ -98,7 +101,7 @@ def user_list(auth, fields=None):
@is_unit_operation([('username', 'user')]) @is_unit_operation([('username', 'user')])
def user_create(operation_logger, auth, username, firstname, lastname, mail, password, def user_create(operation_logger, username, firstname, lastname, mail, password,
mailbox_quota="0"): mailbox_quota="0"):
""" """
Create user Create user
@ -116,12 +119,15 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.app import app_ssowatconf from yunohost.app import app_ssowatconf
from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.password import assert_password_is_strong_enough
from yunohost.utils.ldap import _get_ldap_interface
# Ensure sufficiently complex password # Ensure sufficiently complex password
assert_password_is_strong_enough("user", password) assert_password_is_strong_enough("user", password)
ldap = _get_ldap_interface()
# Validate uniqueness of username and mail in LDAP # Validate uniqueness of username and mail in LDAP
auth.validate_uniqueness({ ldap.validate_uniqueness({
'uid': username, 'uid': username,
'mail': mail 'mail': mail
}) })
@ -143,7 +149,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
raise YunohostError('mail_unavailable') raise YunohostError('mail_unavailable')
# Check that the mail domain exists # Check that the mail domain exists
if mail.split("@")[1] not in domain_list(auth)['domains']: if mail.split("@")[1] not in domain_list()['domains']:
raise YunohostError('mail_domain_unknown', domain=mail.split("@")[1]) raise YunohostError('mail_domain_unknown', domain=mail.split("@")[1])
operation_logger.start() operation_logger.start()
@ -177,7 +183,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
} }
# If it is the first user, add some aliases # If it is the first user, add some aliases
if not auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=*'): if not ldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=*'):
attr_dict['mail'] = [attr_dict['mail']] + aliases attr_dict['mail'] = [attr_dict['mail']] + aliases
# If exists, remove the redirection from the SSO # If exists, remove the redirection from the SSO
@ -197,14 +203,14 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
except IOError as e: except IOError as e:
raise YunohostError('ssowat_persistent_conf_write_error', error=e.strerror) raise YunohostError('ssowat_persistent_conf_write_error', error=e.strerror)
if auth.add('uid=%s,ou=users' % username, attr_dict): if ldap.add('uid=%s,ou=users' % username, attr_dict):
# 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 # Update SFTP user group
memberlist = auth.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid'] memberlist = ldap.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid']
memberlist.append(username) memberlist.append(username)
if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}): if ldap.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}):
try: try:
# Attempt to create user home folder # Attempt to create user home folder
subprocess.check_call( subprocess.check_call(
@ -213,7 +219,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
if not os.path.isdir('/home/{0}'.format(username)): if not os.path.isdir('/home/{0}'.format(username)):
logger.warning(m18n.n('user_home_creation_failed'), logger.warning(m18n.n('user_home_creation_failed'),
exc_info=1) exc_info=1)
app_ssowatconf(auth) app_ssowatconf()
# TODO: Send a welcome mail to user # TODO: Send a welcome mail to user
logger.success(m18n.n('user_created')) logger.success(m18n.n('user_created'))
hook_callback('post_user_create', hook_callback('post_user_create',
@ -225,7 +231,7 @@ def user_create(operation_logger, auth, username, firstname, lastname, mail, pas
@is_unit_operation([('username', 'user')]) @is_unit_operation([('username', 'user')])
def user_delete(operation_logger, auth, username, purge=False): def user_delete(operation_logger, username, purge=False):
""" """
Delete user Delete user
@ -236,34 +242,37 @@ def user_delete(operation_logger, auth, username, purge=False):
""" """
from yunohost.app import app_ssowatconf from yunohost.app import app_ssowatconf
from yunohost.hook import hook_callback from yunohost.hook import hook_callback
from yunohost.utils.ldap import _get_ldap_interface
operation_logger.start() operation_logger.start()
if auth.remove('uid=%s,ou=users' % username):
ldap = _get_ldap_interface()
if ldap.remove('uid=%s,ou=users' % username):
# 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 # Update SFTP user group
memberlist = auth.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid'] memberlist = ldap.search(filter='cn=sftpusers', attrs=['memberUid'])[0]['memberUid']
try: try:
memberlist.remove(username) memberlist.remove(username)
except: except:
pass pass
if auth.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}): if ldap.update('cn=sftpusers,ou=groups', {'memberUid': memberlist}):
if purge: if purge:
subprocess.call(['rm', '-rf', '/home/{0}'.format(username)]) subprocess.call(['rm', '-rf', '/home/{0}'.format(username)])
subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)]) subprocess.call(['rm', '-rf', '/var/mail/{0}'.format(username)])
else: else:
raise YunohostError('user_deletion_failed') raise YunohostError('user_deletion_failed')
app_ssowatconf(auth) app_ssowatconf()
hook_callback('post_user_delete', args=[username, purge]) hook_callback('post_user_delete', args=[username, purge])
logger.success(m18n.n('user_deleted')) logger.success(m18n.n('user_deleted'))
@is_unit_operation([('username', 'user')], exclude=['auth', 'change_password']) @is_unit_operation([('username', 'user')], exclude=['change_password'])
def user_update(operation_logger, auth, username, firstname=None, lastname=None, mail=None, def user_update(operation_logger, username, firstname=None, lastname=None, mail=None,
change_password=None, add_mailforward=None, remove_mailforward=None, change_password=None, add_mailforward=None, remove_mailforward=None,
add_mailalias=None, remove_mailalias=None, mailbox_quota=None): add_mailalias=None, remove_mailalias=None, mailbox_quota=None):
""" """
@ -284,13 +293,15 @@ def user_update(operation_logger, auth, username, firstname=None, lastname=None,
from yunohost.domain import domain_list, _get_maindomain from yunohost.domain import domain_list, _get_maindomain
from yunohost.app import app_ssowatconf from yunohost.app import app_ssowatconf
from yunohost.utils.password import assert_password_is_strong_enough from yunohost.utils.password import assert_password_is_strong_enough
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
attrs_to_fetch = ['givenName', 'sn', 'mail', 'maildrop'] attrs_to_fetch = ['givenName', 'sn', 'mail', 'maildrop']
new_attr_dict = {} new_attr_dict = {}
domains = domain_list(auth)['domains'] domains = domain_list()['domains']
# Populate user informations # Populate user informations
result = auth.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch) result = ldap.search(base='ou=users,dc=yunohost,dc=org', filter='uid=' + username, attrs=attrs_to_fetch)
if not result: if not result:
raise YunohostError('user_unknown', user=username) raise YunohostError('user_unknown', user=username)
user = result[0] user = result[0]
@ -321,7 +332,7 @@ def user_update(operation_logger, auth, username, firstname=None, lastname=None,
'webmaster@' + main_domain, 'webmaster@' + main_domain,
'postmaster@' + main_domain, 'postmaster@' + main_domain,
] ]
auth.validate_uniqueness({'mail': mail}) ldap.validate_uniqueness({'mail': mail})
if mail[mail.find('@') + 1:] not in domains: if mail[mail.find('@') + 1:] not in domains:
raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:]) raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:])
if mail in aliases: if mail in aliases:
@ -334,7 +345,7 @@ def user_update(operation_logger, auth, username, firstname=None, lastname=None,
if not isinstance(add_mailalias, list): if not isinstance(add_mailalias, list):
add_mailalias = [add_mailalias] add_mailalias = [add_mailalias]
for mail in add_mailalias: for mail in add_mailalias:
auth.validate_uniqueness({'mail': mail}) ldap.validate_uniqueness({'mail': mail})
if mail[mail.find('@') + 1:] not in domains: if mail[mail.find('@') + 1:] not in domains:
raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:]) raise YunohostError('mail_domain_unknown', domain=mail[mail.find('@') + 1:])
user['mail'].append(mail) user['mail'].append(mail)
@ -374,15 +385,15 @@ def user_update(operation_logger, auth, username, firstname=None, lastname=None,
operation_logger.start() operation_logger.start()
if auth.update('uid=%s,ou=users' % username, new_attr_dict): if ldap.update('uid=%s,ou=users' % username, new_attr_dict):
logger.success(m18n.n('user_updated')) logger.success(m18n.n('user_updated'))
app_ssowatconf(auth) app_ssowatconf()
return user_info(auth, username) return user_info(username)
else: else:
raise YunohostError('user_update_failed') raise YunohostError('user_update_failed')
def user_info(auth, username): def user_info(username):
""" """
Get user informations Get user informations
@ -390,6 +401,10 @@ def user_info(auth, username):
username -- Username or mail to get informations username -- Username or mail to get informations
""" """
from yunohost.utils.ldap import _get_ldap_interface
ldap = _get_ldap_interface()
user_attrs = [ user_attrs = [
'cn', 'mail', 'uid', 'maildrop', 'givenName', 'sn', 'mailuserquota' 'cn', 'mail', 'uid', 'maildrop', 'givenName', 'sn', 'mailuserquota'
] ]
@ -399,7 +414,7 @@ def user_info(auth, username):
else: else:
filter = 'uid=' + username filter = 'uid=' + username
result = auth.search('ou=users,dc=yunohost,dc=org', filter, user_attrs) result = ldap.search('ou=users,dc=yunohost,dc=org', filter, user_attrs)
if result: if result:
user = result[0] user = result[0]
@ -469,24 +484,24 @@ def user_info(auth, username):
import yunohost.ssh import yunohost.ssh
def user_ssh_allow(auth, username): def user_ssh_allow(username):
return yunohost.ssh.user_ssh_allow(auth, username) return yunohost.ssh.user_ssh_allow(username)
def user_ssh_disallow(auth, username): def user_ssh_disallow(username):
return yunohost.ssh.user_ssh_disallow(auth, username) return yunohost.ssh.user_ssh_disallow(username)
def user_ssh_list_keys(auth, username): def user_ssh_list_keys(username):
return yunohost.ssh.user_ssh_list_keys(auth, username) return yunohost.ssh.user_ssh_list_keys(username)
def user_ssh_add_key(auth, username, key, comment): def user_ssh_add_key(username, key, comment):
return yunohost.ssh.user_ssh_add_key(auth, username, key, comment) return yunohost.ssh.user_ssh_add_key(username, key, comment)
def user_ssh_remove_key(auth, username, key): def user_ssh_remove_key(username, key):
return yunohost.ssh.user_ssh_remove_key(auth, username, key) return yunohost.ssh.user_ssh_remove_key(username, key)
# #
# End SSH subcategory # End SSH subcategory

View file

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
""" License
Copyright (C) 2019 YunoHost
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program; if not, see http://www.gnu.org/licenses
"""
import atexit
from moulinette.core import init_authenticator
# We use a global variable to do some caching
# to avoid re-authenticating in case we call _get_ldap_authenticator multiple times
_ldap_interface = None
def _get_ldap_interface():
global _ldap_interface
if _ldap_interface is None:
# Instantiate LDAP Authenticator
AUTH_IDENTIFIER = ('ldap', 'as-root')
AUTH_PARAMETERS = {'uri': 'ldapi://%2Fvar%2Frun%2Fslapd%2Fldapi',
'base_dn': 'dc=yunohost,dc=org',
'user_rdn': 'gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth'}
_ldap_interface = init_authenticator(AUTH_IDENTIFIER, AUTH_PARAMETERS)
return _ldap_interface
# Add this to properly close / delete the ldap interface / authenticator
# when Python exits ...
# Otherwise there's a risk that some funky error appears at the very end
# of the command due to Python stuff being unallocated in wrong order.
def _destroy_ldap_interface():
global _ldap_interface
if _ldap_interface is not None:
del _ldap_interface
atexit.register(_destroy_ldap_interface)