Работаем с OU – вставка, удаление, правка. Работа с LDAP в Qt. Часть 8
Сегодня мы рассмотрим работу с OU – организационными единицами в каталоге LDAP на примере Active Directory.
Модернизируем классы
В LDAP может быть множество типов записей, в общем случае тип записи определяется её классом. Я рекомендую прочитать эту статью - https://habr.com/ru/post/538662/, прежде мы продолжим. В ней подробно рассмотрена иерархия LDAP.
Сегодня помимо Пользователей мы начнём работать с OU, а в последующей статье рассмотрим Контакты.
С точки зрения LDAP запись OU и запись Пользователь, отличаются только классом, который установлен для данной записи.
Например, для Пользователя указываются классы:
objectClass = organizationalPerson, person, top, user
Для OU указываются классы:
objectClass = organizationalUnit, person
Класс QLdapUser содержит методы, позволяющие заполнить этот список, но не устанавливает значение для атрибута objectClass.Давайте это исправим, но сначала модернизируем все классы.
В одной из прошлых статей мы создали класс для работы с группами, в нынешний проект он не попал, давайте исправим это и скопируем его в наш проект из этой статьи.
Базовый класс QLdapEntity
Во всех классах для работы с элементами LPDAP мы использовали методы:
QString getXXXXXValue(QString key) const
void setXXXXValue(const QString &key, const QLdapEntryValues &value) const
Код которых полностью совпадал. Давайте уберем это дублирование кода, для этого добавим новый класс – QLdapEntity
Заголовок:
#ifndef QLDAPENTITY_H
#define QLDAPENTITY_H
#include <QString>
#include "qldap.h"
class QLdapEntity
{
public:
explicit QLdapEntity(QLdapEntry *entry);
QString getEntityValue(const QString &key) const;
void setEntityValue(const QString &key, const QLdapEntryValues &value) const;
QString toString() const;
QString operator [](const QString &index) const;
QLdapEntry *getEntry() const;
private:
QLdapEntry *entry;
};
QDebug operator<<(QDebug debug, const QLdapEntity &entity);
QDebug operator<<(QDebug debug, const QLdapEntity *entity);
#endif // QLDAPENTITY_H
Реализация:
#include "qldapentity.h"
#include <QDebug>
QLdapEntity::QLdapEntity(QLdapEntry *entry)
{
this->entry = entry;
}
QString QLdapEntity::getEntityValue(const QString &key) const
{
return (*this->entry)[key].join(",");
}
void QLdapEntity::setEntityValue(const QString &key, const QLdapEntryValues &value) const
{
(*this->entry)[key] = value;
}
QString QLdapEntity::toString() const
{
QString s;
QTextStream out(&s);
out << "QLdapEntity( ";
for(QLdapEntry::iterator i=this->entry->begin();i!=this->entry->end();++i)
{
out << i.key() << ": " << i.value().join(",") << ", ";
}
out << " )";
return s;
}
QDebug operator<<(QDebug debug, const QLdapEntity &entity)
{
QDebugStateSaver saver(debug);
debug.nospace() << "QLdapEntity( ";
for(QLdapEntry::iterator i=entity.getEntry()->begin();i!=entity.getEntry()->end();++i)
{
debug.nospace() << i.key() << ": " << i.value().join(",") << ", ";
}
debug.nospace() << " )";
return debug;
}
QDebug operator<<(QDebug debug, const QLdapEntity *entity)
{
QDebugStateSaver saver(debug);
debug.nospace() << *entity;
return debug;
}
QString QLdapEntity::operator[] (const QString &index) const
{
assert(index.compare("") != 0);
return this->getEntityValue(index);
}
QLdapEntry *QLdapEntity::getEntry() const
{
return entry;
}
Как видите, мы добавили перегрузку операторов и метод getEntry(), этот геттер позволяет получить прямой доступ к значениям QLdapEntity.
Так же был переписана перегрузка << теперь будут выводиться все действительные значения QLdapEntity.
Теперь нам нужно в классы QLdapUser и QLdapGroup добавить наследование от QLdapEntity и внести некоторые изменения.
Модификация класса QLdapUser
Наследуем класс от QLdapEntity и удалим ненужные методы, в результате класс измениться:
Заголовок:
#ifndef QLDAPUSER_H
#define QLDAPUSER_H
#include <QString>
#include "qldap.h"
#include "qldapentity.h"
#define QLDAP_AD_USER 0
class QLdapUser : public QLdapEntity
{
public:
explicit QLdapUser(QLdapEntry *user);
QString getDisplayName() const;
QString getGivenName() const;
QString getInitials() const;
QString getOfficePhone() const;
QString getDepartment() const;
QString getTitle() const;
QString getUserPrincipalName() const;
QString getCellPhone() const;
QString getSamAccountName() const;
QString getPath() const;
QString getEmail() const;
QString getStreetAddress() const;
QString getOffice() const;
QString getCompany() const;
QString getFax() const;
void setDisplayName(const QString &value) const;
void setGivenName(const QString &value) const;
void setInitials(const QString &value) const;
void setOfficePhone(const QString &value) const;
void setDepartment(const QString &value) const;
void setTitle(const QString &value) const;
void setUserPrincipalName(const QString &value) const;
void setMobilePhone(const QString &value) const;
void setSamAccountName(const QString &value) const;
void setPath(const QString &value) const;
void setEmail(const QString &value) const;
void setStreetAddress(const QString &value) const;
void setOffice(const QString &value) const;
void setCompany(const QString &value) const;
void setFax(const QString &value) const;
void setName(const QString &value) const;
};
QDebug operator<<(QDebug debug, const QLdapUser &user);
QDebug operator<<(QDebug debug, const QLdapUser *user);
#endif // QLDAPUSER_H
Реализация:
#include "qldapuser.h"
#include "qldapuser.h"
#include <QDebug>
#include <QString>
QLdapUser::QLdapUser(QLdapEntry *user) : QLdapEntity(user)
{
}
QString QLdapUser::getDisplayName() const
{
return this->getEntityValue("displayName");
}
QString QLdapUser::getInitials() const
{
return this->getEntityValue("initials");
}
QString QLdapUser::getOfficePhone() const
{
return this->getEntityValue("otherTelephone");
}
QString QLdapUser::getDepartment() const
{
return this->getEntityValue("department");
}
QString QLdapUser::getTitle() const
{
return this->getEntityValue("title");
}
QString QLdapUser::getUserPrincipalName() const
{
return this->getEntityValue("userPrincipalName");
}
QString QLdapUser::getCellPhone() const
{
return this->getEntityValue("mobile");
}
QString QLdapUser::getSamAccountName() const
{
return this->getEntityValue("sAMAccountName");
}
QString QLdapUser::getPath() const
{
return this->getEntityValue("distinguishedName");
}
QString QLdapUser::getEmail() const
{
return this->getEntityValue("mail");
}
QString QLdapUser::getStreetAddress() const
{
return this->getEntityValue("streetAddress");
}
QString QLdapUser::getOffice() const
{
return this->getEntityValue("physicalDeliveryOfficeName");
}
QString QLdapUser::getCompany() const
{
return this->getEntityValue("company");
}
QString QLdapUser::getFax() const
{
return this->getEntityValue("facsimileTelephoneNumber");
}
void QLdapUser::setDisplayName(const QString &value) const
{
this->setEntityValue("displayName",QStringList(value));
}
void QLdapUser::setGivenName(const QString &value) const
{
this->setEntityValue("givenName",QStringList(value));
}
void QLdapUser::setInitials(const QString &value) const
{
this->setEntityValue("initials",QStringList(value));
}
void QLdapUser::setOfficePhone(const QString &value) const
{
this->setEntityValue("otherTelephone",QStringList(value));
}
void QLdapUser::setDepartment(const QString &value) const
{
this->setEntityValue("department",QStringList(value));
}
void QLdapUser::setTitle(const QString &value) const
{
this->setEntityValue("title",QStringList(value));
}
void QLdapUser::setUserPrincipalName(const QString &value) const
{
this->setEntityValue("userPrincipalName",QStringList(value));
}
void QLdapUser::setMobilePhone(const QString &value) const
{
this->setEntityValue("mobile",QStringList(value));
}
void QLdapUser::setSamAccountName(const QString &value) const
{
this->setEntityValue("sAMAccountName",QStringList(value));
}
void QLdapUser::setPath(const QString &value) const
{
this->setEntityValue("distinguishedName",QStringList(value));
}
void QLdapUser::setEmail(const QString &value) const
{
this->setEntityValue("mail",QStringList(value));
}
void QLdapUser::setStreetAddress(const QString &value) const
{
this->setEntityValue("streetAddress",QStringList(value));
}
void QLdapUser::setOffice(const QString &value) const
{
this->setEntityValue("physicalDeliveryOfficeName",QStringList(value));
}
void QLdapUser::setCompany(const QString &value) const
{
this->setEntityValue("company",QStringList(value));
}
void QLdapUser::setFax(const QString &value) const
{
this->setEntityValue("facsimileTelephoneNumber",QStringList(value));
}
void QLdapUser::setName(const QString &value) const
{
this->setEntityValue("name",QStringList(value));
}
QDebug operator<<(QDebug debug, const QLdapUser &user)
{
QDebugStateSaver saver(debug);
debug.nospace() << "QLdapUserAD( ";
debug.nospace() << (QLdapEntity *)&user;
debug.nospace() << " )";
return debug;
}
QDebug operator<<(QDebug debug, const QLdapUser *user)
{
QDebugStateSaver saver(debug);
debug.nospace() << *user;
return debug;
}
Обратите внимание, мы удалили перегрузку оператора [], так как она уже добавлена в базовый класс.
Но оставили перегрузку << для QDebug так как она объявляется отдельно от класса и должна соответствовать типу нашего класса.
В сеттерах и геттерах мы используем методы базового класса setEntityValue и getEntityValue.
Изменим строку:
u.setUserValue("objectClass",QStringList({"user","person","top","organizationalPerson"}));
на
u.setEntityValue("objectClass",QStringList({"user","person","top","organizationalPerson"}));
Запустим сборку – всё работает без ошибок.
Теперь отладка выводит содержимое только заполненных атрибутов:
QLdapUser( QLdapEntity( "physicalDeliveryOfficeName": "104", "objectClass": "user,person,top,organizationalPerson", "name": "Иванов И. И.", "displayName": "Иванов Иван Иванович", "otherTelephone": "+7(495)12300024", "company": "Altunin Soft", "streetAddress": "Ленина 1", "givenName": "Иванов И. И.", "department": "Бухгалтерия", "title": "Бухгалтер", "facsimileTelephoneNumber": "", "initials": "И.", "mail": "IvanovII@altuninvv.local", "mobile": "+7(495)876-16-18", ) )
Новый класс QLdapUserAD
Несмотря на то, что AD полностью поддерживает LDAP, возможно различие в классах записей, а значит и доступных атрибутах, используемых в AD.
Как было сказано выше в LDAP тип записи зависит от классов, которые ей назначены, поэтому мы должны инициализировать objectClass нужным значением, при создании экземпляра класса.
Для этого добавим новый класс QLdapUserAD и наследуем его от QLdapUser
Заголовок:
#ifndef QLDAPUSERAD_H
#define QLDAPUSERAD_H
#include "qldapuser.h"
class QLdapUserAD : public QLdapUser
{
public:
explicit QLdapUserAD(QLdapEntry *user);
};
QDebug operator<<(QDebug debug, const QLdapUserAD &user);
QDebug operator<<(QDebug debug, const QLdapUserAD *user);
#endif // QLDAPUSERAD_H
Реализация:
#include "qldapuserad.h"
#include <QDebug>
QLdapUserAD::QLdapUserAD(QLdapEntry *user) : QLdapUser(user)
{
this->setEntityValue("objectClass",QStringList({"user","person","top","organizationalPerson"}));
}
QDebug operator<<(QDebug debug, const QLdapUserAD &user)
{
QDebugStateSaver saver(debug);
debug.nospace() << "QLdapUserAD( ";
debug.nospace() << (QLdapEntity *)&user;
debug.nospace() << " )";
return debug;
}
QDebug operator<<(QDebug debug, const QLdapUserAD *user)
{
QDebugStateSaver saver(debug);
debug.nospace() << *user;
return debug;
}
В конструкторе главной формы заменим QLdapUser на QLdapUserAD.
Удалим строку:
u.setEntityValue("objectClass",QStringList({"user","person","top","organizationalPerson"}));
Запустим – всё отработало как обычно, значит своей правкой мы ничего не сломали!
Подобным образом был модернизирован класс – QldapGroup.
Создаем класс для OU
Очистим конструктор главной формы от кода для работы с пользователями, он нам больше не понадобится.
OU является такой же записью как и пользователь, разница между ними в присвоенном классе:
objectClass = organizationalUnit
Давайте добавим класс для OU - QLdapOU:
Заголовок:
#ifndef QLDAPOU_H
#define QLDAPOU_H
#include <QString>
#include "qldap.h"
#include "qldapentity.h"
class QLdapOU : public QLdapEntity
{
public:
explicit QLdapOU(QLdapEntry *ou);
void setDecription(const QString &value) const;
QString getDecription() const;
void setName(const QString &value) const;
QString getName() const;
};
QDebug operator<<(QDebug debug, const QLdapOU &user);
QDebug operator<<(QDebug debug, const QLdapOU *user);
#endif // QLDAPOU_H
Реализация:
#include "qldapou.h"
#include <QDebug>
QLdapOU::QLdapOU(QLdapEntry *ou) : QLdapEntity(ou)
{
this->setEntityValue("objectClass",QStringList({"organizationalUnit"}));
}
QString QLdapOU::getDecription() const
{
return this->getEntityValue("description");
}
void QLdapOU::setDecription(const QString &value) const
{
this->setEntityValue("description",QStringList(value));
}
void QLdapOU::setName(const QString &value) const
{
this->setEntityValue("name",QStringList(value));
}
QString QLdapOU::getName() const
{
return this->getEntityValue("name");
}
QDebug operator<<(QDebug debug, const QLdapOU &user)
{
QDebugStateSaver saver(debug);
debug.nospace() << "QLdapOU( ";
debug.nospace() << (QLdapEntity *)&user;
debug.nospace() << " )";
return debug;
}
QDebug operator<<(QDebug debug, const QLdapOU *user)
{
QDebugStateSaver saver(debug);
debug.nospace() << *user;
return debug;
}
В данный момент в OU нас интересуют атрибуты name, description и ou.
Добавляем новое OU
Добавим новое OU – otdel5
В конструктор главной формы добавим код:
QLdapEntry *ou1 = new QLdapEntry();
QLdapOU ou = QLdapOU(ou1);
ou.setName("otdel5");
ou.setDecription("Отдел №5");
qDebug() << ou;
QLdapMod *mod2 = new QLdapMod(ou1, LDAP_MOD_ADD);
LDAPMod **m2 = mod2->getMods();
result = ldap->add("OU=Company,DC=altuninvv,DC=local", ou1, m2);
delete mod2;
if ( result != LDAP_SUCCESS )
{
QString msg = QString("QLDAP ou add() error: ") + QString(ldap_err2string(result));
qDebug("%s",msg.toLatin1().constData());
//return;
}
Запустим:
QLdapOU( QLdapEntity( "name": "otdel5", "description": "Отдел №5", "ou": "otdel5", "objectClass": "organizationalUnit", ) )
GetMods
OP: 0
new dn = "CN=otdel5,OU=Company,DC=altuninvv,DC=local"
Added
QLDAP ou add() error: Insufficient access
Close result = Success
Как видите, не хватает прав на создание OU.
Добавление прав для создания OU в AD
В предыдущих статьях мы уже настраивали права доступа для добавления пользователей и правки атрибутов.
На этот раз, в дополнение к предыдущим разрешениям, установите галочки напротив:
Создание объектов: Подразделение (Create Organizational Unit Objects)
Удаление объектов: Подразделение (Delete Organizational Unit Objects)
Запустим:
QLdapOU( QLdapEntity( "name": "otdel5", "description": "Отдел №5", "objectClass": "organizationalUnit", ) )
GetMods
OP: 0
new dn = "OU=otdel5,OU=Company,DC=altuninvv,DC=local"
Added
Close result = Success
Проверим админку AD:
OU добавлена.
Удаление OU
Попробуем удалить OU, добавим код выше кода создания OU, таким образом у нас всегда будет новый элемент.
result = ldap->del("ou=otdel5,OU=Company,DC=altuninvv,DC=local");
if ( result != LDAP_SUCCESS )
{
QString msg = QString("QLDAP OU del() error: ") + QString(ldap_err2string(result));
qDebug("%s",msg.toLatin1().constData());
//return;
}
Запустим:
GetMods
OP: 0
Delete DN = "ou=otdel5,OU=Company,DC=altuninvv,DC=local"
Deleted
Вы можете через админку AD поменять описание созданной OU и запустить код еще раз. После запуска название измениться.
Правка OU
Давайте изменим описание OU:
QLdapEntry *oue = new QLdapEntry();
QLdapOU ou2 = QLdapOU(oue);
ou2.setDecription("Новый Отдел №5");
QLdapMod *mod1 = new QLdapMod(oue, LDAP_MOD_REPLACE);
LDAPMod **m1 = mod1->getMods();
result = ldap->edit("ou=otdel5,OU=Company,DC=altuninvv,DC=local", m1);
delete mod1;
Запустим:
GetMods
OP: 2
Edit DN = "ou=otdel5,OU=Company,DC=altuninvv,DC=local"
Edited
Обратите внимание, вы не можете переименовать OU таким способом, при попытке изменить атрибут name вы получите ошибку:
QLDAP OU edit() error: Operation not allowed on RDN
Для переименования используется функция OpenLDAP - ldap_rename_s(), но о ней мы поговорим в одной из следующих статей.
Заключение
Сегодня мы рассмотрели добавление, правку и удаление OU из каталога LDAP.
Была произведена модернизация классов для работы с записями LDAP – введен класс QLdapEntity от которого теперь наследуются классы QLdapUser и QLdapGroup.
Были внесены изменения в классы QLdapUser и QLdapGroup.
Мы добавили класс для работы с OU – QLdapOU.
Настроили права доступа в AD для создания и удаления OU.
Привели примеры добавления удаления, правки OU в каталоге LDAP.
Скачать исходный код вы можете на GitFlic
Добавить комментарий