Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Программирование под Unix/Linux > программная авторизация на сервере AD


Автор: out51d3r 19.7.2015, 05:44
Доброго времени суток товарищи!
Пишу приложение... И чтобы пользоваться этим приложением, пользователю надо авторизоваться. Для авторизации используются сервер Active Directory, в которой хранится информация о пользователе.
1. Пользователь запускает приложение.
2. Приложение просит авторизоваться.
3. Пользователь вводит свой windows логин и пароль.
4. Приложение смотрит, в какие группы безопасности включен пользователь.
5. В зависимости от группы безопасности, будет генерироваться соответсвующий интерфейс приложения. То есть, если пользователь будет только в группе Domain Users, то для такого пользователя будет минимальный интерфейс. Например, если он состоит в группе Domain Operator, то программа предоставит дополнительный функционал.

Так, как пишу в среде Linux, хотелось бы узнать - кто как вообще работает в этом направлении. По-началу, решил использовать OpenLDAP, но примеры слишком устаревшие. В нете предлагают использовать ldap_simple_bind, но такой функции нет. Вместо неё ldap_sasl_bind и ldap_gssapi_bind. 

Пожалуйста, будьте добры, подсобите примерчиком или ссылками на русскоязычное руководство.

(up)

Автор: tzirechnoy 19.7.2015, 19:46
1) Никаких русскоязычных руководств нет. Забудь вообще. Он-лайн дискуссий нормальных и англоязычных нет, потому можно сначала в русские потыкаться -- мало что потеряешь. Но руководства английские -- бывают, а русские -- устаревшая кривопереведённая лажа.

2) Подозреваю, что тебе придётся настраивать kerberos (клиента). Ну, во всяком случае, когда у меня были домены AD, я всегда из линукса успешно подключался к LDAP через kerberos. Потому -- скорее ldap_gssapi_bind.

3) Впрочем, это пока не очень важно -- поскольку сначала -- сделай, чтобы просто ldapsearch (команда такая) -- работал. Возможно, kerberos и не потребуется, достаточно будет какого-нибудь логина с паролем. У меня, впрочем, kerberos всегда был, в частности, потому, что это удобно.

По словам "ldapsearch connect to AD" или как-то так можно найти сравнительно много полезных советов. Когда у тебя получится -- у тебя будет большэ знаний, и либо работающий kerberos либо знание, что можно обойтись sasl.

4) И да, GSS API -- это как раз фишка кербероса. Ну, разработчики из MIT его в своё время разрабатывали как типа универсальное -- но по факту, ничего полезного кроме кербероса оно не поддержывает. Так что ldap_gssapi_bind -- это про kerberos.
А SASL -- это типа более универсальное API (теоретически там есть и аутэнтификацыя по сертификатам, и через kerberos), но в основном используется для безопасной передачи пары логин+пароль.

Автор: out51d3r 20.7.2015, 09:57
tzirechnoy, спасибо за пинок в нужном направлении)

В терминале Linux, поигрался с ldapsearh и добился результатов:
ldapsearch -H "ldap://192.168.1.1" -D "[email protected]" -w "password" -b "dc=lab,dc=local"

Получил список пользователей и различные параметры. И, самое главное, получил список (поле MemberOf) в каких группах состоит пользователь!
И всё же, какую функцию использует тулза ldapsearch, чтобы забиндиться к серверу?

Код

#include <ldap.h>
#include <iostream>
using namespace std;

int main()
{
    LDAP *ld;
    cout << ldap_initialize(&ld, "ldap://myhost"); // тут всё OK
    cout << dap_gssapi_bind(ld, "login@domain", "password") << endl; // а вот тут ERROR -12


Писал на скорую руку. В функциях подставлены актуальные значения аргументов.

Автор: out51d3r 7.8.2015, 11:09
Не вкуривается. Нужна экстра-помощь. Тов. гуру, помогите пожалуйста!
Скорее всего, придётся работать в синхронном режиме. Неужели никто не писал LDAP-клиентов?

Автор: tzirechnoy 7.8.2015, 14:16
Что невкуривается-то?

Я как-то был уверен, что при выборе из двух функцый, когда неполучится с одной -- ты успешно как-нибудь попробуешь другую.

Впрочем, за прошэдщэе время можно было или посмотреть, какая функцыя используется при помощи ltrace, или выкачать исходники openldap, пересобрать пакет, убедится, что пересобранный работает, найти в исходниках подозрительные места, вставить в них отладочную печать, ещё раз пересобрать пакет, и посмотреть, какие функцыи и с какими аргументами вызываются, напрямую.

Автор: out51d3r 12.8.2015, 12:49
Не могу осилить ldap_sasl_interactive_bind_s. В параметрах этой функции, следует передавать другую функцию, которая будет произвоить аутентификацию SASL..

Автор: tzirechnoy 12.8.2015, 20:05
Не производить аутэнтификацыю, а передавать username/realm/password.

Прототип описан в man ldap_sasl_interactive_bind_s -- это тот, который int (LDAP_SASL_INTERACT_PROC)(LDAP *id...

Последний параметр -- указатель на некоторое количество sasl_interact_t из описания cyrus SASL, которые надо заполнить.

Ну, и ещё одно -- я не пробовал AD+SASL. Пробовал только AD+kerberos. В прошлый раз я как-то позабыл, что, действительно, кроме GSS и SASL в LDAP есть simple -- возможно, что для авторизацыи в AD потребуется именно он.

Автор: out51d3r 23.8.2015, 19:23
Наконец-то разобрался...

Код

#include <iostream>
#include <ldap.h>
#include <sasl/sasl.h>

using namespace std;
struct sasl_defaults
{
string username;
string password;
};

// обработка передачи кред 
int do_interact(LDAP *ds, unsigned flags, void *indefaults, void *in)
{
sasl_defaults *defaults = static_cast<sasl_defaults *>(indefaults);
sasl_interact_t *interact = (sasl_interact_t *)in;
if (ds == NULL)
{
return LDAP_PARAM_ERROR;
}

while(interact->id != SASL_CB_LIST_END)
{
const char *dflt = static_cast<const char *>(interact->defresult);
switch(interact->id)
{
case SASL_CB_GETREALM:
dflt = NULL;
break;
case SASL_CB_USER:
case SASL_CB_AUTHNAME:
dflt = defaults->username.c_str();
break;
case SASL_CB_PASS:
dflt = defaults->password.c_str();
break;
}
interact->result = (dflt && *dflt) ? dflt : static_cast<const char *>("");
interact->len = strlen(static_cast<const char *>(interact->result));
interact++;
}
return LDAP_SUCCESS;
}
int main(int argc, char *argv[])
{
LDAP *ld;
int rc, version = 3;
rc = ldap_initialize(&ld, "ldap://192.168.1.1");  // сервер АД
cout << "ldap_init = " << rc << endl;
if(rc != LDAP_SUCCESS)
return 1;
if( (rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)) != LDAP_OPT_SUCCESS)
return 2;
cout << "ldap_set_option protocol 3" << endl;
if( (rc = ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF)) != LDAP_OPT_SUCCESS)
return 3;
cout << "ldap_set_option refferals off" << endl;
// Креды 
sasl_defaults def;
def.username = "ИМЯ ПОЛЬЗОВАТЕЛЯ БЕЗ ДОМЕННОЙ ЧАСТИ";
def.password = "ПАРОЛЬ";
ldap_set_option(ld, LDAP_OPT_CONNECT_ASYNC, LDAP_OPT_OFF);
ldap_set_option(ld, LDAP_OPT_SASL_METHOD, (void*)"DIGEST-MD5");

rc = ldap_sasl_interactive_bind_s(ld, NULL, "DIGEST-MD5", NULL, NULL, LDAP_SASL_AUTOMATIC, do_interact, &def);
cout << "BIND RESUT = " << rc << endl;
cout << "error = " << ldap_err2string(rc) << endl;
return ldap_unbind_ext(ld, NULL, NULL);
}


Автор: korol 4.3.2016, 13:05
Модератор: Сообщение скрыто.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)