:: /
: accountsservice
Sources Gear Bugs and FR Repocop
: accountsservice-23.13.9.patch
generate-version.sh | 3 +-
meson.build | 5 +
meson_options.txt | 1 +
po/cs.po | 53 ++-
po/ru.po | 53 ++-
src/daemon.c | 41 ++-
src/libaccountsservice/act-user-manager.c | 14 +-
src/user-classify.c | 2 +
subprojects/mocklibc.wrap | 2 +
.../packagefiles/mocklibc-print-indent.diff | 13 +
tests/dbusmock/accounts_service.py | 393 ---------------------
tests/mock_services/accounts_service.py | 393 +++++++++++++++++++++
tests/test-libaccountsservice.py | 4 +-
13 files changed, 531 insertions(+), 446 deletions(-)
diff --git a/generate-version.sh b/generate-version.sh
index 3f88bff..8375c86 100755
--- a/generate-version.sh
+++ b/generate-version.sh
@@ -4,11 +4,10 @@ exec 3>&2 2> /dev/null
SRCDIR=$(dirname "$0")
cd "$SRCDIR"
CWD=$(realpath "$PWD")
-TOPLEVEL_WORKING_DIR=$(realpath "$(git rev-parse --show-toplevel)")
exec 2>&3
# If it's not from a git checkout, assume it's from a tarball
-if [ "$TOPLEVEL_WORKING_DIR" != "$CWD" ]; then
+if ! git rev-parse --is-inside-git-dir > /dev/null 2>&1; then
VERSION_FROM_DIR_NAME=$(basename "$CWD" | sed -n 's/^accountsservice-\([^-]*\)$/\1/p')
if [ -n "$VERSION_FROM_DIR_NAME" ]; then
diff --git a/meson.build b/meson.build
index 4a509e7..04455f6 100644
--- a/meson.build
+++ b/meson.build
@@ -198,6 +198,10 @@ if admin_group == ''
endif
endif
+default_user_groups = ','.join(get_option('default_user_groups'))
+
+config_h.set_quoted('DEFAULT_USER_GROUPS', default_user_groups)
+
extra_admin_groups = ','.join(get_option('extra_admin_groups'))
config_h.set_quoted('ADMIN_GROUP', admin_group)
@@ -247,6 +251,7 @@ meson.add_install_script(
output = '\n' + meson.project_name() + ' was configured with the following options:\n'
output += '** DocBook documentation build: ' + enable_docbook.to_string() + '\n'
output += '** Administrator group: ' + admin_group + '\n'
+output += '** Default user groups: ' + default_user_groups + '\n'
output += '** Extra administrator groups: ' + extra_admin_groups + '\n'
output += '** GDM configuration: ' + gdm_conf_file + '\n'
output += '** LightDM configuration: ' + lightdm_conf_file
diff --git a/meson_options.txt b/meson_options.txt
index b34a0fa..47cc9c9 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -4,6 +4,7 @@ option('lightdmconffile', type: 'string', value: '/etc/lightdm/lightdm.conf', de
option('admin_group', type: 'string', value: '', description: 'Set group for administrative accounts')
option('extra_admin_groups', type: 'array', value: [], description: 'Comma-separated list of extra groups that administrator users are part of')
+option('default_user_groups', type: 'array', value: [], description: 'Comma-separated list of groups that all users are part of by default')
option('minimum_uid', type: 'integer', value: 1000, description: 'Set minimum uid for human users')
option('elogind', type: 'boolean', value: false, description: 'Use elogind')
diff --git a/po/cs.po b/po/cs.po
index 7cdc2b4..c948c99 100644
--- a/po/cs.po
+++ b/po/cs.po
@@ -1,62 +1,77 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# Marek Černocký <marek@manet.cz>, 2011
# Ondrej Novak <novak@linux.com>, 2011
+# Daniel Rusek <mail@asciiwolf.com>, 2023
msgid ""
msgstr ""
"Project-Id-Version: accounts service\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-17 09:48-0500\n"
-"PO-Revision-Date: 2019-02-22 14:19+0000\n"
-"Last-Translator: halfline <halfline@gmail.com>\n"
-"Language-Team: Czech (http://www.transifex.com/freedesktop/accountsservice/language/cs/)\n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/accountsservice/"
+"accountsservice/issues\n"
+"POT-Creation-Date: 2022-07-31 12:33+0000\n"
+"PO-Revision-Date: 2023-05-31 15:16+0200\n"
+"Last-Translator: Daniel Rusek <mail@asciiwolf.com>\n"
+"Language-Team: Czech (http://www.transifex.com/freedesktop/accountsservice/"
+"language/cs/)\n"
+"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: cs\n"
-"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
+"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
+"X-Generator: Poedit 3.3.1\n"
-#: ../data/org.freedesktop.accounts.policy.in.h:1
+#: data/org.freedesktop.accounts.policy.in:11
msgid "Change your own user data"
msgstr "Změnit své vlastní údaje"
-#: ../data/org.freedesktop.accounts.policy.in.h:2
+#: data/org.freedesktop.accounts.policy.in:12
msgid "Authentication is required to change your own user data"
msgstr "Pro změnu svých vlastních údajů je vyžadována autentizace"
-#: ../data/org.freedesktop.accounts.policy.in.h:3
+#: data/org.freedesktop.accounts.policy.in:21
+msgid "Change your own user password"
+msgstr "Změnit své vlastní heslo"
+
+#: data/org.freedesktop.accounts.policy.in:22
+msgid "Authentication is required to change your own user password"
+msgstr "Pro změnu svého vlastního hesla je vyžadována autentizace"
+
+#: data/org.freedesktop.accounts.policy.in:31
msgid "Manage user accounts"
msgstr "Spravovat uživatelské účty"
-#: ../data/org.freedesktop.accounts.policy.in.h:4
+#: data/org.freedesktop.accounts.policy.in:32
msgid "Authentication is required to change user data"
msgstr "Pro změnu údajů o uživateli je vyžadována autentizace"
-#: ../data/org.freedesktop.accounts.policy.in.h:5
+#: data/org.freedesktop.accounts.policy.in:41
msgid "Change the login screen configuration"
msgstr "Změnit nastavení přihlašovací obrazovky"
-#: ../data/org.freedesktop.accounts.policy.in.h:6
+#: data/org.freedesktop.accounts.policy.in:42
msgid "Authentication is required to change the login screen configuration"
msgstr "Pro změnu nastavení přihlašovací obrazovky je vyžadována autentizace"
-#: ../src/main.c:127
+#: src/main.c:225
msgid "Output version information and exit"
msgstr "Zobrazit informace o verzi a ukončit program"
-#: ../src/main.c:128
+#: src/main.c:226
msgid "Replace existing instance"
msgstr "Nahradit současnou instanci"
-#: ../src/main.c:129
+#: src/main.c:227
msgid "Enable debugging code"
msgstr "Povolit ladicí kód"
-#: ../src/main.c:149
+#: src/main.c:246
msgid ""
"Provides D-Bus interfaces for querying and manipulating\n"
"user account information."
-msgstr "Poskytuje rozhraní D-Bus pro zobrazování a změny\ninformací o uživatelských účtech"
+msgstr ""
+"Poskytuje rozhraní D-Bus pro zobrazování a změny\n"
+"informací o uživatelských účtech"
diff --git a/po/ru.po b/po/ru.po
index 58d173a..5040794 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -1,61 +1,76 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
-#
+#
# Translators:
# Yuri Kozlov <yuray@komyakino.ru>, 2011
msgid ""
msgstr ""
"Project-Id-Version: accounts service\n"
-"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-01-17 09:48-0500\n"
-"PO-Revision-Date: 2019-02-22 14:19+0000\n"
-"Last-Translator: halfline <halfline@gmail.com>\n"
-"Language-Team: Russian (http://www.transifex.com/freedesktop/accountsservice/language/ru/)\n"
+"Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/accountsservice/"
+"accountsservice/issues\n"
+"POT-Creation-Date: 2022-07-31 12:33+0000\n"
+"PO-Revision-Date: 2023-04-08 17:12+0300\n"
+"Last-Translator: Aleksandr Melman <Alexmelman88@gmail.com>\n"
+"Language-Team: Russian (http://www.transifex.com/freedesktop/accountsservice/"
+"language/ru/)\n"
+"Language: ru\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Language: ru\n"
-"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
+"n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || "
+"(n%100>=11 && n%100<=14)? 2 : 3);\n"
+"X-Generator: Poedit 3.2.2\n"
-#: ../data/org.freedesktop.accounts.policy.in.h:1
+#: data/org.freedesktop.accounts.policy.in:11
msgid "Change your own user data"
msgstr "Изменить личные пользовательские данные"
-#: ../data/org.freedesktop.accounts.policy.in.h:2
+#: data/org.freedesktop.accounts.policy.in:12
msgid "Authentication is required to change your own user data"
msgstr "Для изменения личных пользовательских данных требуется аутентификация"
-#: ../data/org.freedesktop.accounts.policy.in.h:3
+#: data/org.freedesktop.accounts.policy.in:21
+msgid "Change your own user password"
+msgstr "Изменить личный пароль пользователя"
+
+#: data/org.freedesktop.accounts.policy.in:22
+msgid "Authentication is required to change your own user password"
+msgstr "Для изменения личного пароля пользователя требуется аутентификация"
+
+#: data/org.freedesktop.accounts.policy.in:31
msgid "Manage user accounts"
msgstr "Управление учётными записями пользователей"
-#: ../data/org.freedesktop.accounts.policy.in.h:4
+#: data/org.freedesktop.accounts.policy.in:32
msgid "Authentication is required to change user data"
msgstr "Для изменения пользовательских данных требуется аутентификация"
-#: ../data/org.freedesktop.accounts.policy.in.h:5
+#: data/org.freedesktop.accounts.policy.in:41
msgid "Change the login screen configuration"
msgstr "Изменить настройки экрана входа в систему"
-#: ../data/org.freedesktop.accounts.policy.in.h:6
+#: data/org.freedesktop.accounts.policy.in:42
msgid "Authentication is required to change the login screen configuration"
msgstr "Для изменения настроек экрана входа в систему требуется аутентификация"
-#: ../src/main.c:127
+#: src/main.c:225
msgid "Output version information and exit"
msgstr "Вывод информации о версии и выход из программы"
-#: ../src/main.c:128
+#: src/main.c:226
msgid "Replace existing instance"
msgstr "Заменить существующий экземпляр"
-#: ../src/main.c:129
+#: src/main.c:227
msgid "Enable debugging code"
msgstr "Включить отладочный код"
-#: ../src/main.c:149
+#: src/main.c:246
msgid ""
"Provides D-Bus interfaces for querying and manipulating\n"
"user account information."
-msgstr "Предоставляет интерфейс D-Bus для опроса и изменения\nинформации об учётных данных пользователей."
+msgstr ""
+"Предоставляет интерфейс D-Bus для опроса и изменения\n"
+"информации об учётных данных пользователей."
diff --git a/src/daemon.c b/src/daemon.c
index aa9d050..6e36795 100644
--- a/src/daemon.c
+++ b/src/daemon.c
@@ -1311,6 +1311,7 @@ daemon_create_user_authorized_cb (Daemon *daemon,
g_autoptr (GError) error = NULL;
const gchar *argv[9];
g_autofree gchar *admin_groups = NULL;
+ g_autofree gchar *user_groups = NULL;
if (getpwnam (cd->user_name) != NULL) {
throw_error (context, ERROR_USER_EXISTS, "A user with name '%s' already exists", cd->user_name);
@@ -1323,11 +1324,32 @@ daemon_create_user_authorized_cb (Daemon *daemon,
argv[1] = "-m";
argv[2] = "-c";
argv[3] = cd->real_name;
+
+ /* Build default user groups */
+ g_auto (GStrv) user_groups_array = NULL;
+ g_autoptr (GStrvBuilder) user_groups_builder = g_strv_builder_new ();
+
+ if (DEFAULT_USER_GROUPS != NULL && DEFAULT_USER_GROUPS[0] != '\0') {
+ g_auto (GStrv) default_user_groups = NULL;
+ default_user_groups = g_strsplit (DEFAULT_USER_GROUPS, ",", 0);
+
+ for (gsize i = 0; default_user_groups[i] != NULL; i++) {
+ if (getgrnam (default_user_groups[i]) != NULL)
+ g_strv_builder_add (user_groups_builder, default_user_groups[i]);
+ else
+ g_warning ("Group %s doesn’t exist: not adding the user to it", default_user_groups[i]);
+ }
+ }
+ user_groups_array = g_strv_builder_end (user_groups_builder);
+ user_groups = g_strjoinv (",", user_groups_array);
+
if (cd->account_type == ACCOUNT_TYPE_ADMINISTRATOR) {
g_auto (GStrv) admin_groups_array = NULL;
g_autoptr (GStrvBuilder) admin_groups_builder = g_strv_builder_new ();
g_strv_builder_add (admin_groups_builder, ADMIN_GROUP);
+ /* Add default user groups to admin groups */
+ g_strv_builder_add (admin_groups_builder, user_groups);
if (EXTRA_ADMIN_GROUPS != NULL && EXTRA_ADMIN_GROUPS[0] != '\0') {
g_auto (GStrv) extra_admin_groups = NULL;
@@ -1340,6 +1362,7 @@ daemon_create_user_authorized_cb (Daemon *daemon,
g_warning ("Extra admin group %s doesn’t exist: not adding the user to it", extra_admin_groups[i]);
}
}
+
admin_groups_array = g_strv_builder_end (admin_groups_builder);
admin_groups = g_strjoinv (",", admin_groups_array);
@@ -1349,9 +1372,11 @@ daemon_create_user_authorized_cb (Daemon *daemon,
argv[7] = cd->user_name;
argv[8] = NULL;
} else if (cd->account_type == ACCOUNT_TYPE_STANDARD) {
- argv[4] = "--";
- argv[5] = cd->user_name;
- argv[6] = NULL;
+ argv[4] = "-G";
+ argv[5] = user_groups;
+ argv[6] = "--";
+ argv[7] = cd->user_name;
+ argv[8] = NULL;
} else {
throw_error (context, ERROR_FAILED, "Don't know how to add user of type %d", cd->account_type);
return;
@@ -1803,9 +1828,8 @@ load_autologin (Daemon *daemon,
else if (dm_type == DISPLAY_MANAGER_TYPE_GDM)
return load_autologin_gdm (daemon, name, enabled, error);
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _ ("Unsupported Display Manager"));
-
- return FALSE;
+ /* Default to GDM for backward compatibility */
+ return load_autologin_gdm (daemon, name, enabled, error);
}
static gboolean
@@ -1824,7 +1848,7 @@ save_autologin_gdm (Daemon *daemon,
PATH_GDM_CUSTOM,
G_KEY_FILE_KEEP_COMMENTS,
&local_error)) {
- /* It's OK for custom.conf to not exist, we will make it */
+ /* It's OK if the GDM config file doesn't exist, since we will make it, if necessary */
if (!g_error_matches (local_error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) {
g_propagate_error (error, g_steal_pointer (&local_error));
return FALSE;
@@ -1885,7 +1909,8 @@ save_autologin (Daemon *daemon,
else if (dm_type == DISPLAY_MANAGER_TYPE_GDM)
return save_autologin_gdm (daemon, name, enabled, error);
- return FALSE;
+ /* Default to GDM for backward compatibility */
+ return save_autologin_gdm (daemon, name, enabled, error);
}
gboolean
diff --git a/src/libaccountsservice/act-user-manager.c b/src/libaccountsservice/act-user-manager.c
index 61b4da5..7afe713 100644
--- a/src/libaccountsservice/act-user-manager.c
+++ b/src/libaccountsservice/act-user-manager.c
@@ -153,6 +153,7 @@ typedef struct
};
char *object_path;
char *description;
+ gulong ready_id;
} ActUserManagerFetchUserRequest;
typedef struct
@@ -717,6 +718,8 @@ on_user_destroyed (ActUserManager *manager,
ActUserManagerPrivate *priv = act_user_manager_get_instance_private (manager);
GSList *node;
+ priv->new_users = g_slist_remove (priv->new_users, destroyed_user);
+
node = priv->fetch_user_requests;
while (node != NULL) {
ActUserManagerFetchUserRequest *request;
@@ -1754,6 +1757,7 @@ load_new_session_incrementally (ActUserManagerNewSession *new_session)
break;
case ACT_USER_MANAGER_NEW_SESSION_STATE_LOADED:
break;
+ case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
default:
g_assert_not_reached ();
}
@@ -1781,6 +1785,7 @@ free_fetch_user_request (ActUserManagerFetchUserRequest *request)
g_cancellable_cancel (request->cancellable);
g_object_unref (request->cancellable);
+ g_clear_signal_handler (&request->ready_id, manager);
g_debug ("ActUserManager: unrefing manager owned by fetch user request");
g_object_unref (manager);
@@ -1823,7 +1828,7 @@ on_user_manager_maybe_ready_for_request (ActUserManager *manager
g_debug ("ActUserManager: user manager now loaded, proceeding with fetch user request for %s",
request->description);
- g_signal_handlers_disconnect_by_func (manager, on_user_manager_maybe_ready_for_request, request);
+ g_clear_signal_handler (&request->ready_id, manager);
request->state++;
fetch_user_incrementally (request);
@@ -1845,8 +1850,10 @@ fetch_user_incrementally (ActUserManagerFetchUserRequest *request)
} else {
g_debug ("ActUserManager: waiting for user manager to load before finding %s",
request->description);
- g_signal_connect (manager, "notify::is-loaded",
- G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
+ g_assert (request->ready_id == 0);
+ request->ready_id =
+ g_signal_connect (manager, "notify::is-loaded",
+ G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
}
break;
@@ -2270,6 +2277,7 @@ load_seat_incrementally (ActUserManager *manager)
case ACT_USER_MANAGER_SEAT_STATE_LOADED:
g_debug ("ActUserManager: Seat loading sequence complete");
break;
+ case ACT_USER_MANAGER_NEW_SESSION_STATE_UNLOADED:
default:
g_assert_not_reached ();
}
diff --git a/src/user-classify.c b/src/user-classify.c
index 2a38a77..ef8b864 100644
--- a/src/user-classify.c
+++ b/src/user-classify.c
@@ -108,6 +108,8 @@ is_invalid_shell (const char *shell)
return TRUE;
} else if (g_strcmp0 (basename, "false") == 0) {
return TRUE;
+ } else if (g_strcmp0 (basename, "null") == 0) {
+ return TRUE;
}
return ret;
diff --git a/subprojects/mocklibc.wrap b/subprojects/mocklibc.wrap
index af82298..539ee83 100644
--- a/subprojects/mocklibc.wrap
+++ b/subprojects/mocklibc.wrap
@@ -8,3 +8,5 @@ source_hash = b2236a6af1028414783e9734a46ea051916ec226479d6a55a3bb823bff68f120
patch_url = https://wrapdb.mesonbuild.com/v1/projects/mocklibc/1.0/2/get_zip
patch_filename = mocklibc-1.0-2-wrap.zip
patch_hash = 0280f96a2eeb3c023e5acf4e00cef03d362868218d4a85347ea45137c0ef6c56
+
+diff_files = mocklibc-print-indent.diff
diff --git a/subprojects/packagefiles/mocklibc-print-indent.diff b/subprojects/packagefiles/mocklibc-print-indent.diff
new file mode 100644
index 0000000..4aaed40
--- /dev/null
+++ b/subprojects/packagefiles/mocklibc-print-indent.diff
@@ -0,0 +1,13 @@
+diff -up mocklibc-1.0/src/netgroup-debug.c.print-indent mocklibc-1.0/src/netgroup-debug.c
+--- mocklibc-1.0/src/netgroup-debug.c.print-indent 2023-04-11 10:20:53.717381559 -0400
++++ mocklibc-1.0/src/netgroup-debug.c 2023-04-11 10:21:02.296270333 -0400
+@@ -21,6 +21,9 @@
+ #include <stdio.h>
+ #include <stdlib.h>
+
++void print_indent (FILE *stream,
++ unsigned int indent);
++
+ void netgroup_debug_print_entry(struct entry *entry, FILE *stream, unsigned int indent) {
+ print_indent(stream, indent);
+
diff --git a/tests/dbusmock/accounts_service.py b/tests/dbusmock/accounts_service.py
deleted file mode 100644
index 6f36efe..0000000
--- a/tests/dbusmock/accounts_service.py
+++ /dev/null
@@ -1,393 +0,0 @@
-'''Accounts Service D-Bus mock template'''
-
-# This program is free software; you can redistribute it and/or modify it under
-# the terms of the GNU Lesser General Public License as published by the Free
-# Software Foundation; either version 3 of the License, or (at your option) any
-# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
-# of the license.
-
-__author__ = 'Marco Trevisan'
-__email__ = 'marco.trevisan@canonical.com'
-__copyright__ = '(c) 2021 Canonical Ltd.'
-__license__ = 'LGPL 3+'
-
-import sys
-import time
-
-import dbus
-from dbusmock import MOCK_IFACE, mockobject
-
-BUS_NAME = 'org.freedesktop.Accounts'
-MAIN_OBJ = '/org/freedesktop/Accounts'
-MAIN_IFACE = 'org.freedesktop.Accounts'
-USER_IFACE = MAIN_IFACE + '.User'
-SYSTEM_BUS = True
-
-DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'
-
-
-def get_user_path(uid):
- return '/org/freedesktop/Accounts/User{}'.format(uid)
-
-
-def load(mock, parameters=None):
- parameters = parameters if parameters else {}
- mock.mock_users = {}
- mock.cached_users = []
- mock.automatic_login_users = set()
- mock.users_auto_uids = 2000
-
- mock.AddProperties(MAIN_IFACE, mock.GetAll(MAIN_IFACE))
-
- for uid, name in parameters.get('users', {}).items():
- mock.AddUser(uid, name, DEFAULT_USER_PASSWORD, {}, {})
-
-def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None):
- if properties is None:
- properties = mock.GetAll(interface)
- elif isinstance(properties, str):
- properties = [properties]
-
- if isinstance(properties, (list, set)):
- properties = {p: mock.Get(interface, p) for p in properties}
- elif not isinstance(properties, dict):
- raise TypeError('Unsupported properties type')
-
- mock.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', (
- interface, properties, []))
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}a{sv}',
- out_signature='o')
-def AddUser(self, uid, username, password=DEFAULT_USER_PASSWORD,
- overrides=None, password_policy_overrides=None):
- '''Add user via uid and username and optionally overriding properties
-
- Returns the new object path.
- '''
- path = get_user_path(uid)
- default_props = {
- 'Uid': dbus.UInt64(uid),
- 'UserName': username,
- 'RealName': username[0].upper() + username[1:] + ' Fake',
- 'AccountType': dbus.Int32(1),
- 'AutomaticLogin': False,
- 'BackgroundFile': '',
- 'Email': '{}@python-dbusmock.org'.format(username),
- 'FormatsLocale': 'C',
- 'HomeDirectory': '/nonexisting/mock-home/{}'.format(username),
- 'IconFile': '',
- 'InputSources': dbus.Array([], signature='a{ss}'),
- 'Language': 'C',
- 'Languages': dbus.Array([], signature='s'),
- 'LocalAccount': True,
- 'Location': '',
- 'Locked': False,
- 'LoginFrequency': dbus.UInt64(0),
- 'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
- 'LoginTime': dbus.Int64(0),
- 'PasswordHint': 'Remember it, come on!',
- 'PasswordMode': 0,
- 'Session': 'mock-session',
- 'SessionType': 'wayland',
- 'Shell': '/usr/bin/zsh',
- 'SystemAccount': False,
- 'XHasMessages': False,
- 'XKeyboardLayouts': dbus.Array([], signature='s'),
- 'XSession': 'mock-xsession',
- }
- default_props.update(overrides if overrides else {})
- self.AddObject(path, USER_IFACE, default_props, [])
-
- had_users = len(self.mock_users) != 0
- had_multiple_users = len(self.mock_users) > 1
- user = mockobject.objects[path]
- user.password = password
- user.properties = default_props
- user.pwd_expiration_policy = {
- 'expiration_time': sys.maxsize,
- 'last_change_time': int(time.time()),
- 'min_days_between_changes': 0,
- 'max_days_between_changes': 0,
- 'days_to_warn': 0,
- 'days_after_expiration_until_lock': 0,
- }
- user.pwd_expiration_policy.update(
- password_policy_overrides if password_policy_overrides else {})
- self.mock_users[uid] = default_props
-
- self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])
-
- if not had_users:
- emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
- elif not had_multiple_users and len(self.mock_users) > 1:
- emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
-
- return path
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
-def ListMockUsers(self):
- """ List the mock users that have been created """
- return [get_user_path(uid) for uid in self.mock_users.keys()]
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
-def AddAutoLoginUser(self, username):
- """ Enable autologin for an user """
- path = self.FindUserByName(username)
- self.automatic_login_users.add(path)
- user = mockobject.objects[path]
- set_user_property(user, 'AutomaticLogin', True)
- emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
- return path
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
-def RemoveAutoLoginUser(self, username):
- """ Disables autologin for an user """
- path = self.FindUserByName(username)
- self.automatic_login_users.remove(path)
- user = mockobject.objects[path]
- set_user_property(user, 'AutomaticLogin', False)
- emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
- return path
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='ssi', out_signature='o')
-def CreateUser(self, name, fullname, account_type):
- """ Creates an user using the default API """
- try:
- self.FindUserByName(name)
- found = True
- except dbus.exceptions.DBusException:
- found = False
-
- if found:
- raise dbus.exceptions.DBusException(
- 'User {} already exists'.format(name),
- name='org.freedesktop.Accounts.Error.Failed')
-
- self.users_auto_uids += 1
-
- return self.AddUser(self.users_auto_uids, name, DEFAULT_USER_PASSWORD, {
- 'RealName': fullname, 'AccountType': account_type}, {})
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='xb')
-def DeleteUser(self, uid, _remove_files):
- """ Removes a created user """
- path = self.FindUserById(uid)
-
- had_multiple_users = len(self.mock_users) > 1
- self.RemoveObject(path)
- self.mock_users.pop(uid)
- self.automatic_login_users.discard(path)
-
- self.EmitSignal(MAIN_IFACE, 'UserDeleted', 'o', [path])
-
- if len(self.mock_users) == 0:
- emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
- elif had_multiple_users and len(self.mock_users) < 2:
- emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
-def CacheUser(self, username):
- """ Cache an user """
- path = self.FindUserByName(username)
- self.cached_users.append(path)
- return path
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s')
-def UncacheUser(self, username):
- """ Removes an user from the cache """
- path = self.FindUserByName(username)
- self.cached_users.remove(path)
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='', out_signature='ao')
-def ListCachedUsers(self):
- """ Lists the cached users """
- return self.cached_users
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
-def FindUserById(_self, uid):
- """ Finds an user by its user id """
- user = mockobject.objects.get(get_user_path(uid), None)
- if not user:
- raise dbus.exceptions.DBusException(
- 'No such user exists',
- name='org.freedesktop.Accounts.Error.Failed')
- return get_user_path(uid)
-
-
-@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
-def FindUserByName(self, username):
- """ Finds an user form its name """
- try:
- [user_id] = [uid for uid, props in self.mock_users.items()
- if props['UserName'] == username]
- except ValueError as e:
- raise dbus.exceptions.DBusException(
- 'No such user exists: {}'.format(e),
- name='org.freedesktop.Accounts.Error.Failed')
- return get_user_path(user_id)
-
-
-@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
- out_signature='a{sv}')
-def GetAll(self, interface):
- """ Implements the GetAll dbus properties interface method.
-
- This allows to override the getters using dynamic values.
- """
- if interface == MAIN_IFACE:
- return {
- 'DaemonVersion': 'dbus-mock-0.1',
- 'HasNoUsers': len(self.mock_users) == 0,
- 'HasMultipleUsers': len(self.mock_users) > 1,
- 'AutomaticLoginUsers': dbus.Array(self.automatic_login_users,
- signature='o'),
- }
- if interface == USER_IFACE:
- return self.properties
- return dbus.Dictionary({}, signature='sv')
-
-
-@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
- out_signature='v')
-def Get(self, interface, prop):
- """ Implements the Get dbus properties interface method.
-
- This allows to override the getters using dynamic values, via GetAll.
- """
- return self.GetAll(interface)[prop]
-
-
-def set_user_property(user, property_name, value):
- """ Set an user property and emits the relative signals """
- if user.properties[property_name] == value:
- return
- user.properties[property_name] = value
- emit_properties_changed(user, USER_IFACE, property_name)
- user.EmitSignal(USER_IFACE, 'Changed', '', [])
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetUserName(self, user_name):
- set_user_property(self, 'UserName', user_name)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetRealName(self, real_name):
- set_user_property(self, 'RealName', real_name)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetEmail(self, email):
- set_user_property(self, 'Email', email)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetLanguage(self, language):
- set_user_property(self, 'Language', language)
-
-
-@dbus.service.method(USER_IFACE, in_signature='as')
-def SetLanguages(self, languages):
- set_user_property(self, 'Languages', dbus.Array(languages, signature='s'))
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetXSession(self, x_session):
- set_user_property(self, 'XSession', x_session)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetSession(self, session):
- set_user_property(self, 'Session', session)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetSessionType(self, session_type):
- set_user_property(self, 'SessionType', session_type)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetLocation(self, location):
- set_user_property(self, 'Location', location)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetHomeDirectory(self, home_directory):
- set_user_property(self, 'HomeDirectory', home_directory)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetShell(self, shell):
- set_user_property(self, 'Shell', shell)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetIconFile(self, icon_file):
- set_user_property(self, 'IconFile', icon_file)
-
-
-@dbus.service.method(USER_IFACE, in_signature='b')
-def SetLocked(self, locked):
- set_user_property(self, 'Locked', locked)
-
-
-@dbus.service.method(USER_IFACE, in_signature='i')
-def SetAccountType(self, account_type):
- set_user_property(self, 'AccountType', account_type)
-
-
-@dbus.service.method(USER_IFACE, in_signature='i')
-def SetPasswordMode(self, password_mode):
- set_user_property(self, 'PasswordMode', password_mode)
-
-
-@dbus.service.method(USER_IFACE, in_signature='s')
-def SetPasswordHint(self, hint):
- set_user_property(self, 'PasswordHint', hint)
-
-
-@dbus.service.method(USER_IFACE, in_signature='ss')
-def SetPassword(self, password, hint):
- self.password = password
- self.SetPasswordHint(hint)
-
-
-@dbus.service.method(USER_IFACE, in_signature='b')
-def SetAutomaticLogin(self, automatic_login):
- manager = mockobject.objects[MAIN_OBJ]
- if automatic_login:
- manager.AddAutoLoginUser(self.properties['UserName'])
- else:
- manager.RemoveAutoLoginUser(self.properties['UserName'])
-
-
-@dbus.service.method(MOCK_IFACE, in_signature='xxxxxxx')
-def SetUserPasswordExpirationPolicy(self, uid, expiration_time,
- last_change_time, min_days_between_changes,
- max_days_between_changes, days_to_warn,
- days_after_expiration_until_lock):
- user = mockobject.objects[self.FindUserById(uid)]
- user.pwd_expiration_policy = {
- 'expiration_time': expiration_time,
- 'last_change_time': last_change_time,
- 'min_days_between_changes': min_days_between_changes,
- 'max_days_between_changes': max_days_between_changes,
- 'days_to_warn': days_to_warn,
- 'days_after_expiration_until_lock': days_after_expiration_until_lock,
- }
- user.EmitSignal(USER_IFACE, 'Changed', '', [])
-
-
-@dbus.service.method(USER_IFACE, in_signature='', out_signature='xxxxxx')
-def GetPasswordExpirationPolicy(self):
- return tuple(self.pwd_expiration_policy.values())
diff --git a/tests/mock_services/accounts_service.py b/tests/mock_services/accounts_service.py
new file mode 100644
index 0000000..6f36efe
--- /dev/null
+++ b/tests/mock_services/accounts_service.py
@@ -0,0 +1,393 @@
+'''Accounts Service D-Bus mock template'''
+
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option) any
+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
+# of the license.
+
+__author__ = 'Marco Trevisan'
+__email__ = 'marco.trevisan@canonical.com'
+__copyright__ = '(c) 2021 Canonical Ltd.'
+__license__ = 'LGPL 3+'
+
+import sys
+import time
+
+import dbus
+from dbusmock import MOCK_IFACE, mockobject
+
+BUS_NAME = 'org.freedesktop.Accounts'
+MAIN_OBJ = '/org/freedesktop/Accounts'
+MAIN_IFACE = 'org.freedesktop.Accounts'
+USER_IFACE = MAIN_IFACE + '.User'
+SYSTEM_BUS = True
+
+DEFAULT_USER_PASSWORD = 'Pa$$wo0rd'
+
+
+def get_user_path(uid):
+ return '/org/freedesktop/Accounts/User{}'.format(uid)
+
+
+def load(mock, parameters=None):
+ parameters = parameters if parameters else {}
+ mock.mock_users = {}
+ mock.cached_users = []
+ mock.automatic_login_users = set()
+ mock.users_auto_uids = 2000
+
+ mock.AddProperties(MAIN_IFACE, mock.GetAll(MAIN_IFACE))
+
+ for uid, name in parameters.get('users', {}).items():
+ mock.AddUser(uid, name, DEFAULT_USER_PASSWORD, {}, {})
+
+def emit_properties_changed(mock, interface=MAIN_IFACE, properties=None):
+ if properties is None:
+ properties = mock.GetAll(interface)
+ elif isinstance(properties, str):
+ properties = [properties]
+
+ if isinstance(properties, (list, set)):
+ properties = {p: mock.Get(interface, p) for p in properties}
+ elif not isinstance(properties, dict):
+ raise TypeError('Unsupported properties type')
+
+ mock.EmitSignal(dbus.PROPERTIES_IFACE, 'PropertiesChanged', 'sa{sv}as', (
+ interface, properties, []))
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='xssa{sv}a{sv}',
+ out_signature='o')
+def AddUser(self, uid, username, password=DEFAULT_USER_PASSWORD,
+ overrides=None, password_policy_overrides=None):
+ '''Add user via uid and username and optionally overriding properties
+
+ Returns the new object path.
+ '''
+ path = get_user_path(uid)
+ default_props = {
+ 'Uid': dbus.UInt64(uid),
+ 'UserName': username,
+ 'RealName': username[0].upper() + username[1:] + ' Fake',
+ 'AccountType': dbus.Int32(1),
+ 'AutomaticLogin': False,
+ 'BackgroundFile': '',
+ 'Email': '{}@python-dbusmock.org'.format(username),
+ 'FormatsLocale': 'C',
+ 'HomeDirectory': '/nonexisting/mock-home/{}'.format(username),
+ 'IconFile': '',
+ 'InputSources': dbus.Array([], signature='a{ss}'),
+ 'Language': 'C',
+ 'Languages': dbus.Array([], signature='s'),
+ 'LocalAccount': True,
+ 'Location': '',
+ 'Locked': False,
+ 'LoginFrequency': dbus.UInt64(0),
+ 'LoginHistory': dbus.Array([], signature='(xxa{sv})'),
+ 'LoginTime': dbus.Int64(0),
+ 'PasswordHint': 'Remember it, come on!',
+ 'PasswordMode': 0,
+ 'Session': 'mock-session',
+ 'SessionType': 'wayland',
+ 'Shell': '/usr/bin/zsh',
+ 'SystemAccount': False,
+ 'XHasMessages': False,
+ 'XKeyboardLayouts': dbus.Array([], signature='s'),
+ 'XSession': 'mock-xsession',
+ }
+ default_props.update(overrides if overrides else {})
+ self.AddObject(path, USER_IFACE, default_props, [])
+
+ had_users = len(self.mock_users) != 0
+ had_multiple_users = len(self.mock_users) > 1
+ user = mockobject.objects[path]
+ user.password = password
+ user.properties = default_props
+ user.pwd_expiration_policy = {
+ 'expiration_time': sys.maxsize,
+ 'last_change_time': int(time.time()),
+ 'min_days_between_changes': 0,
+ 'max_days_between_changes': 0,
+ 'days_to_warn': 0,
+ 'days_after_expiration_until_lock': 0,
+ }
+ user.pwd_expiration_policy.update(
+ password_policy_overrides if password_policy_overrides else {})
+ self.mock_users[uid] = default_props
+
+ self.EmitSignal(MAIN_IFACE, 'UserAdded', 'o', [path])
+
+ if not had_users:
+ emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
+ elif not had_multiple_users and len(self.mock_users) > 1:
+ emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
+
+ return path
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='', out_signature='ao')
+def ListMockUsers(self):
+ """ List the mock users that have been created """
+ return [get_user_path(uid) for uid in self.mock_users.keys()]
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
+def AddAutoLoginUser(self, username):
+ """ Enable autologin for an user """
+ path = self.FindUserByName(username)
+ self.automatic_login_users.add(path)
+ user = mockobject.objects[path]
+ set_user_property(user, 'AutomaticLogin', True)
+ emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
+ return path
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='s', out_signature='o')
+def RemoveAutoLoginUser(self, username):
+ """ Disables autologin for an user """
+ path = self.FindUserByName(username)
+ self.automatic_login_users.remove(path)
+ user = mockobject.objects[path]
+ set_user_property(user, 'AutomaticLogin', False)
+ emit_properties_changed(self, MAIN_IFACE, 'AutomaticLoginUsers')
+ return path
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='ssi', out_signature='o')
+def CreateUser(self, name, fullname, account_type):
+ """ Creates an user using the default API """
+ try:
+ self.FindUserByName(name)
+ found = True
+ except dbus.exceptions.DBusException:
+ found = False
+
+ if found:
+ raise dbus.exceptions.DBusException(
+ 'User {} already exists'.format(name),
+ name='org.freedesktop.Accounts.Error.Failed')
+
+ self.users_auto_uids += 1
+
+ return self.AddUser(self.users_auto_uids, name, DEFAULT_USER_PASSWORD, {
+ 'RealName': fullname, 'AccountType': account_type}, {})
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='xb')
+def DeleteUser(self, uid, _remove_files):
+ """ Removes a created user """
+ path = self.FindUserById(uid)
+
+ had_multiple_users = len(self.mock_users) > 1
+ self.RemoveObject(path)
+ self.mock_users.pop(uid)
+ self.automatic_login_users.discard(path)
+
+ self.EmitSignal(MAIN_IFACE, 'UserDeleted', 'o', [path])
+
+ if len(self.mock_users) == 0:
+ emit_properties_changed(self, MAIN_IFACE, 'HasNoUsers')
+ elif had_multiple_users and len(self.mock_users) < 2:
+ emit_properties_changed(self, MAIN_IFACE, 'HasMultipleUsers')
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
+def CacheUser(self, username):
+ """ Cache an user """
+ path = self.FindUserByName(username)
+ self.cached_users.append(path)
+ return path
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s')
+def UncacheUser(self, username):
+ """ Removes an user from the cache """
+ path = self.FindUserByName(username)
+ self.cached_users.remove(path)
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='', out_signature='ao')
+def ListCachedUsers(self):
+ """ Lists the cached users """
+ return self.cached_users
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='x', out_signature='o')
+def FindUserById(_self, uid):
+ """ Finds an user by its user id """
+ user = mockobject.objects.get(get_user_path(uid), None)
+ if not user:
+ raise dbus.exceptions.DBusException(
+ 'No such user exists',
+ name='org.freedesktop.Accounts.Error.Failed')
+ return get_user_path(uid)
+
+
+@dbus.service.method(MAIN_IFACE, in_signature='s', out_signature='o')
+def FindUserByName(self, username):
+ """ Finds an user form its name """
+ try:
+ [user_id] = [uid for uid, props in self.mock_users.items()
+ if props['UserName'] == username]
+ except ValueError as e:
+ raise dbus.exceptions.DBusException(
+ 'No such user exists: {}'.format(e),
+ name='org.freedesktop.Accounts.Error.Failed')
+ return get_user_path(user_id)
+
+
+@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='s',
+ out_signature='a{sv}')
+def GetAll(self, interface):
+ """ Implements the GetAll dbus properties interface method.
+
+ This allows to override the getters using dynamic values.
+ """
+ if interface == MAIN_IFACE:
+ return {
+ 'DaemonVersion': 'dbus-mock-0.1',
+ 'HasNoUsers': len(self.mock_users) == 0,
+ 'HasMultipleUsers': len(self.mock_users) > 1,
+ 'AutomaticLoginUsers': dbus.Array(self.automatic_login_users,
+ signature='o'),
+ }
+ if interface == USER_IFACE:
+ return self.properties
+ return dbus.Dictionary({}, signature='sv')
+
+
+@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature='ss',
+ out_signature='v')
+def Get(self, interface, prop):
+ """ Implements the Get dbus properties interface method.
+
+ This allows to override the getters using dynamic values, via GetAll.
+ """
+ return self.GetAll(interface)[prop]
+
+
+def set_user_property(user, property_name, value):
+ """ Set an user property and emits the relative signals """
+ if user.properties[property_name] == value:
+ return
+ user.properties[property_name] = value
+ emit_properties_changed(user, USER_IFACE, property_name)
+ user.EmitSignal(USER_IFACE, 'Changed', '', [])
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetUserName(self, user_name):
+ set_user_property(self, 'UserName', user_name)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetRealName(self, real_name):
+ set_user_property(self, 'RealName', real_name)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetEmail(self, email):
+ set_user_property(self, 'Email', email)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetLanguage(self, language):
+ set_user_property(self, 'Language', language)
+
+
+@dbus.service.method(USER_IFACE, in_signature='as')
+def SetLanguages(self, languages):
+ set_user_property(self, 'Languages', dbus.Array(languages, signature='s'))
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetXSession(self, x_session):
+ set_user_property(self, 'XSession', x_session)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetSession(self, session):
+ set_user_property(self, 'Session', session)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetSessionType(self, session_type):
+ set_user_property(self, 'SessionType', session_type)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetLocation(self, location):
+ set_user_property(self, 'Location', location)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetHomeDirectory(self, home_directory):
+ set_user_property(self, 'HomeDirectory', home_directory)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetShell(self, shell):
+ set_user_property(self, 'Shell', shell)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetIconFile(self, icon_file):
+ set_user_property(self, 'IconFile', icon_file)
+
+
+@dbus.service.method(USER_IFACE, in_signature='b')
+def SetLocked(self, locked):
+ set_user_property(self, 'Locked', locked)
+
+
+@dbus.service.method(USER_IFACE, in_signature='i')
+def SetAccountType(self, account_type):
+ set_user_property(self, 'AccountType', account_type)
+
+
+@dbus.service.method(USER_IFACE, in_signature='i')
+def SetPasswordMode(self, password_mode):
+ set_user_property(self, 'PasswordMode', password_mode)
+
+
+@dbus.service.method(USER_IFACE, in_signature='s')
+def SetPasswordHint(self, hint):
+ set_user_property(self, 'PasswordHint', hint)
+
+
+@dbus.service.method(USER_IFACE, in_signature='ss')
+def SetPassword(self, password, hint):
+ self.password = password
+ self.SetPasswordHint(hint)
+
+
+@dbus.service.method(USER_IFACE, in_signature='b')
+def SetAutomaticLogin(self, automatic_login):
+ manager = mockobject.objects[MAIN_OBJ]
+ if automatic_login:
+ manager.AddAutoLoginUser(self.properties['UserName'])
+ else:
+ manager.RemoveAutoLoginUser(self.properties['UserName'])
+
+
+@dbus.service.method(MOCK_IFACE, in_signature='xxxxxxx')
+def SetUserPasswordExpirationPolicy(self, uid, expiration_time,
+ last_change_time, min_days_between_changes,
+ max_days_between_changes, days_to_warn,
+ days_after_expiration_until_lock):
+ user = mockobject.objects[self.FindUserById(uid)]
+ user.pwd_expiration_policy = {
+ 'expiration_time': expiration_time,
+ 'last_change_time': last_change_time,
+ 'min_days_between_changes': min_days_between_changes,
+ 'max_days_between_changes': max_days_between_changes,
+ 'days_to_warn': days_to_warn,
+ 'days_after_expiration_until_lock': days_after_expiration_until_lock,
+ }
+ user.EmitSignal(USER_IFACE, 'Changed', '', [])
+
+
+@dbus.service.method(USER_IFACE, in_signature='', out_signature='xxxxxx')
+def GetPasswordExpirationPolicy(self):
+ return tuple(self.pwd_expiration_policy.values())
diff --git a/tests/test-libaccountsservice.py b/tests/test-libaccountsservice.py
index 723ab51..f0261b1 100644
--- a/tests/test-libaccountsservice.py
+++ b/tests/test-libaccountsservice.py
@@ -39,7 +39,7 @@ class AccountsServiceTestBase(dbusmock.DBusTestCase):
super().setUp()
if not hasattr(self, '_mock'):
template = os.path.join(
- os.path.dirname(__file__), 'dbusmock/accounts_service.py')
+ os.path.dirname(__file__), 'mock_services/accounts_service.py')
(self._mock, self._mock_obj) = self.spawn_server_template(
template, {}, stdout=subprocess.PIPE)
self._manager = AccountsService.UserManager.get_default()
@@ -88,7 +88,7 @@ class TestAccountsServicePreExistingUser(AccountsServiceTestBase):
'''Test mocking AccountsService with pre-existing user'''
def setUp(self):
template = os.path.join(
- os.path.dirname(__file__), 'dbusmock/accounts_service.py')
+ os.path.dirname(__file__), 'mock_services/accounts_service.py')
(self._mock, self._mock_obj) = self.spawn_server_template(
template, {'users': { 2001: 'pizza' }}, stdout=subprocess.PIPE)
super().setUp()