authservice.cpp 8,8 КБ
Newer Older
1
#include "authservice.h"
2
#include "authdbusservice.h"
sgakerru's avatar
sgakerru включено в состав коммита
3
#include "configuration.h"
4
5
#include "utils.h"

6
#include <QDebug>
7
#include <QMap>
8
#include <QProcess>
9
10
11
#include <QStringList>
#include <QtDBus/QtDBus>

12
13
14
#include <algorithm>

AuthService::AuthService(QObject *parent)
sgakerru's avatar
sgakerru включено в состав коммита
15
16
17
18
    : QObject(parent)
    , config(new Configuration(this, "/mos-auth/mos-auth.conf"))
    , registerUserProcess(new QProcess(this))
    , prepareGuestProcess(new QProcess(this))
19
{
20
    // Удаляем гостя, если он выключен в настройках.
sgakerru's avatar
sgakerru включено в состав коммита
21
22
    if (!guestEnabled()) {
        QProcess *deleteGuest = new QProcess(this);
23
24
25
26
        const QString cmd = R"( sudo /bin/loginctl kill-user --signal KILL 830 ;
                                sudo /usr/sbin/userdel -rf guest
                            )";

27
28
29
        deleteGuest->start("/bin/sh", QStringList() << "-c" << cmd);
    }

sgakerru's avatar
sgakerru включено в состав коммита
30
    // clang-format off
31
32
33
    connect(registerUserProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            [=](int exitCode, QProcess::ExitStatus /*exitStatus*/)
    {
34
        Q_EMIT registerUserFinished(exitCode == 0);
35
36
37
38
39
    });

    connect(prepareGuestProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            [=](int exitCode, QProcess::ExitStatus /*exitStatus*/)
    {
40
        Q_EMIT prepareGuestFinished(exitCode == 0);
41
    });
sgakerru's avatar
sgakerru включено в состав коммита
42
    // clang-format on
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

    this->dbusConnect();
}

void AuthService::dbusConnect()
{
    if (!QDBusConnection::systemBus().isConnected()) {
        qWarning() << "Cannot connect to the D-Bus system bus.";
        return;
    }

    if (!QDBusConnection::systemBus().registerService("org.mos.auth")) {
        qWarning() << qPrintable(QDBusConnection::systemBus().lastError().message());
        return;
    }

    AuthDBusService *dbus = new AuthDBusService(this);
    QDBusConnection::systemBus().registerObject("/", dbus, QDBusConnection::ExportAllSlots);

    connect(dbus, &AuthDBusService::loginCalled, this, &AuthService::login);
63
64
}

65
66
67
68
69
70
71
72
73
74
75
QMap<int, QString> AuthService::initMapRoleToGroup()
{
    QMap<int, QString> res;

    res.insert(Role::Admin, "mos-admin");
    res.insert(Role::Teacher, "mos-teacher");
    res.insert(Role::Student, "mos-student");

    return res;
}

76
77
78
79
QString AuthService::getGroupsFromRoles(const QList<int> &roles, const QString &separator)
{
    QString groups = "";

sgakerru's avatar
sgakerru включено в состав коммита
80
81
    for (int role : roles) {
        if (groups.length() > 0) {
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
            groups += separator;
        }

        groups += mapRoleToGroup.value(role);
    }

    return groups;
}

QString AuthService::getExcludeGroupsFromRoles(const QList<int> &userRoles, const QString &separator)
{
    // Все роли.
    QList<int> allRoles = mapRoleToGroup.keys();

    // Роли, не относящиеся к пользователю (группы, к которым он не принадлежит).
    QList<int> excludedRoles;

sgakerru's avatar
sgakerru включено в состав коммита
99
100
101
102
103
    std::set_difference(allRoles.begin(), //
                        allRoles.end(),
                        userRoles.begin(),
                        userRoles.end(),
                        std::inserter(excludedRoles, excludedRoles.begin()));
104
105
106
107

    return getGroupsFromRoles(excludedRoles, separator);
}

sgakerru's avatar
sgakerru включено в состав коммита
108
void AuthService::registerUser(const QString &obrId, //
109
110
                               const QString &_name,
                               const QString &_login,
111
                               const QString &_pin,
112
                               QList<int> roles)
113
{
sgakerru's avatar
sgakerru включено в состав коммита
114
115
116
    bool obrIdToNumberResult = false;
    const qint64 numericObrId = obrId.toLongLong(&obrIdToNumberResult);

sgakerru's avatar
sgakerru включено в состав коммита
117
    if (!obrIdToNumberResult) {
118
        return Q_EMIT registerUserFinished(false);
sgakerru's avatar
sgakerru включено в состав коммита
119
120
121
    }

    const qint64 uid = 10'000'000 + numericObrId;
122
123

    const QString uid_arg = QString::number(uid);
124
125
126
    const QString login = Utils::shellQuote(_login);
    const QString pin = Utils::shellQuote(_pin);
    const QString name = Utils::shellQuote(_name);
127

sgakerru's avatar
sgakerru включено в состав коммита
128
    if (roles.empty()) {
129
        roles.push_back(Role::Student);
130
131
    }

132
133
134
135
    // Вообще такого не должно быть, что список групп от ролей пустой,
    // так как выше в случае пустого массива с ролями добавляется группа студента (как fallback),
    // но на всякий случай обработаем и этот случай при добавлении commonGroup
    const QString groupsListFromRoles = getGroupsFromRoles(roles);
sgakerru's avatar
sgakerru включено в состав коммита
136
137
138
    const QString groups = Utils::shellQuote(groupsListFromRoles != "" //
                                                 ? groupsListFromRoles + "," + commonGroup
                                                 : commonGroup);
139

140
    const QString exclude_groups = Utils::shellQuote(getExcludeGroupsFromRoles(roles));
141

sgakerru's avatar
sgakerru включено в состав коммита
142
    // Создаем группы mos-teacher, mos-student и mos-admin, если их вдруг нет.
sgakerru's avatar
sgakerru включено в состав коммита
143
    const QString _cmd_admin_group = "(getent group 310 || sudo /usr/sbin/groupadd -g 310 mos-admin)";
144
145
146
    const QString _cmd_teacher_group = "(getent group 311 || sudo /usr/sbin/groupadd -g 311 mos-teacher)";
    const QString _cmd_student_group = "(getent group 312 || sudo /usr/sbin/groupadd -g 312 mos-student)";
    const QString cmd_create_groups = _cmd_admin_group + " && " + _cmd_teacher_group + " && " + _cmd_student_group;
147

sgakerru's avatar
sgakerru включено в состав коммита
148
149
150
151
152
    // Создаем группу для пользователя с gid = `uid_arg`, если её не существует.
    const QString _cmd_groupadd = "sudo /usr/sbin/groupadd -g " + uid_arg + " " + login;
    const QString cmd_create_group = "(getent group " + login + " || " + _cmd_groupadd + ")";

    // Проверяем, существует ли пользователь.
153
    const QString cmd_check_user_exist = "/bin/id -u " + login;
154

sgakerru's avatar
sgakerru включено в состав коммита
155
    // Обновляем группы пользователя (на тот случай, если он уже существует в системе).
sgakerru's avatar
sgakerru включено в состав коммита
156
157
    const QString _cmd_exclude_user_groups =
        "sudo /usr/sbin/usermod -G $(/bin/id -nGz " + login + " | grep -zxv " + exclude_groups + " | tr '\\0' ',' | sed 's/.$/\\n/') " + login;
158
159
    const QString cmd_update_user_groups = "(" + _cmd_exclude_user_groups + " && " + "sudo /usr/sbin/usermod -a -G " + groups + " " + login + ")";

sgakerru's avatar
sgakerru включено в состав коммита
160
161
    // Создаем нового пользователя (если его не было в системе).
    const QString cmd_create_user = "sudo /usr/sbin/useradd -c " + name + " -u " + uid_arg + " -g " + uid_arg + " -G " + groups + " " + login;
162

sgakerru's avatar
sgakerru включено в состав коммита
163
    // Задаем пароль.
164
    const QString cmd_pass = "sudo /usr/sbin/chpasswd <<< " + Utils::shellQuote(_login + ":" + _pin);
165

166
167
168
    // Сбрасываем блокировку пароля (если была).
    const QString cmd_reset_faillock = "sudo /sbin/faillock --user " + login + " --reset";

sgakerru's avatar
sgakerru включено в состав коммита
169
170
    const QString cmd = cmd_create_groups + " && " + cmd_create_group + " && " + "(" + cmd_check_user_exist + " && " + cmd_update_user_groups + " || "
        + cmd_create_user + ")" + " && " + cmd_pass + " && " + cmd_reset_faillock;
171
172
173
174
175
176

    registerUserProcess->start("/bin/sh", QStringList() << "-c" << cmd);
}

void AuthService::prepareGuest()
{
177
178
    const QString _cmd_create_guest = R"(sudo /usr/sbin/useradd -u 830 -c "Гость" -M guest -G )" + commonGroup;

sgakerru's avatar
sgakerru включено в состав коммита
179
180
181
182
    const QString cmd =
        "sudo /bin/loginctl kill-user --signal KILL 830 ; "
        "sudo /usr/sbin/userdel -rf guest ; "
        + _cmd_create_guest + " && " + "sudo /usr/bin/passwd -d guest";
183
184
185
186

    prepareGuestProcess->start("/bin/sh", QStringList() << "-c" << cmd);
}

sgakerru's avatar
sgakerru включено в состав коммита
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
void AuthService::handleEapWifi(const QString &ssid, const QString &login, const QString &pass)
{
    const QString connectionName = "temp-corp-сonnection";

    QProcess *createWifi = new QProcess(this);

    const QString deleteIfExist = QString("nmcli connection delete %1").arg(connectionName);
    const QString checkExist = QString("nmcli connection show %1").arg(connectionName);
    const QString create = QString("nmcli connection add save no type wifi con-name %1 "
                                   "autoconnect no connection.permissions sddm "
                                   "wifi-sec.key-mgmt wpa-eap 802-1x.password-flags 2 "
                                   "802-1x.eap peap 802-1x.phase2-auth mschapv2 "
                                   "802-1x.identity \"%2\" 802-1x.domain-suffix-match %3 ssid %4")
                            .arg(connectionName).arg(login).arg("hq.corp.mos.ru").arg(ssid);
    const QString connectTo = QString("echo %1 | nmcli connection up %2 --ask").arg(pass).arg(connectionName);

    const QString cmd = deleteIfExist + " ; " + checkExist + " || (" + create + " && " + connectTo + ")";
    createWifi->start("/bin/sh", QStringList() << "-c" << cmd);
}

207
208
bool AuthService::guestEnabled() const
{
sgakerru's avatar
sgakerru включено в состав коммита
209
    return config->guestEnabled();
210
}
sgakerru's avatar
sgakerru включено в состав коммита
211
212
213

bool AuthService::mosAuthBtnEnabled() const
{
sgakerru's avatar
sgakerru включено в состав коммита
214
    return config->mosAuthBtnEnabled();
sgakerru's avatar
sgakerru включено в состав коммита
215
}
sgakerru's avatar
sgakerru включено в состав коммита
216
217
218
219
220

bool AuthService::loginLowercaseOnly() const
{
    return config->loginLowercaseOnly();
}