Руководство по безопасности в Lotus Notes

Пример программы DSAPI

Разбить на страницы
Показывать лекцию целиком

Это приложение содержит пример DSAPI-программы, иллюстрирующий аутентификацию Web-пользователя Domino через учетную запись пользователя в операционной системе. Этот пример реализует метод обеспечения единой регистрации на основе DSAPI, описанный в лекции 7, "Принцип единого входа".

В целом эта DSAPI-программа содержит код для использования идентификатора и пароля пользователя в Windows-сети пользователя при запуске фильтра на сервере Domino на основе Windows. При запуске на сервере Domino на основе UNIX, применяется идентификатор и пароль пользователя в системе UNIX.

Пример содержит три файла: основная программа, код для Windows и код для UNIX. Полный исходный код, make-файлы и файлы определений представлены в пакете инструментов Domino 6 C API в папке Samples, в подпапке Admin.

Настройка среды

  • Для использования этого DSAPI-фильтра он должен быть зарегистрирован на сервере Domino в соответствии с описанием, приведенным в разделе "Регистрация DSAPI-фильтра в Domino".
  • Пользователь, выполняющий тестирование этой программы, должен иметь учетную запись пользователя Domino на этом сервере Domino, а также учетную запись пользователя в операционной системе на компьютере, на котором запущен сервер. Сведения о создании учетной записи пользователя Domino для существующей учетной записи пользователя в операционной системе см. в разделе "Создание учетной записи пользователя Domino для существующего пользователя операционной системы".
  • Для тестирования этой программы попробуйте открыть базу данных на сервере Domino из Web-браузера. Убедитесь в корректности настройки ACL этой базы данных. Для удобства установите уровень доступа Reader (Читатель) для учетной записи Default и уровень доступа No Access (Нет доступа) для учетной записи Anonymous (Аноним). Установка уровня доступа No Access для учетной записи Anonymous (Аноним) вызывает принудительную аутентификацию.
  • Регистрация DSAPI-фильтра в Domino

  • Скомпилируйте пример программы и скопируйте DLL в программный каталог сервера Domino.
  • Запустите сервер Domino.
  • Из Notes UI откройте базу данных каталога сервера Lotus Domino (базу данных names.nsf).
  • В представлении Server (Сервер) > Servers (Серверы) откройте документ Server данного сервера.
  • На вкладке Internet Protocols (интернет-протоколы) введите имя DLL в поле имен файлов DSAPI-фильтров.
  • Сохраните документ.
  • Создание учетной записи пользователя Domino для существующего пользователя операционной системы

  • Запустите сервер Domino.
  • Запустите Domino Administrator.
  • Убедитесь в том, что поле Server (Сервер) указывает на сервер, а не на Local. Если оно указывает на Local, измените это значение в меню File (Файл) – Open Server (Открыть сервер) таким образом, чтобы оно указывало на сервер Domino.
  • Выделите представление People (Люди) на левой панели.
  • В выпадающем меню People (Люди) на правой панели выберите действие Register (Регистрация).
  • Введите значения в поля First name (Имя), Last name (Фамилия), Short name (Короткое имя) и Password (Пароль). Короткое имя должно совпадать с именем пользователя в учетной записи операционной системы.
  • Нажмите кнопку Register (Регистрация) для создания пользователя Domino.
  • Закройте Domino Administrator.
  • Обновите или отключите сервер Domino.
  • Запуск примера DSAPI-программы secdom

    Примечание (только для серверов Windows). Для аутентификации с использованием DSAPI-фильтра в Windows, для пользователя операционной системы должна быть включена политика безопасности пользователя Act as part of the operating system (Работа в режиме операционной системы). Если определены политики уровня домена, они также должны назначать пользователю это право.

    Если для пользователя Windows не установлена эта политика безопасности, аутентификация будет неуспешной и в консоль сервера будет выведена ошибка.

    Чтобы назначить политику безопасности пользователя Windows для определенного пользователя, просмотрите документацию Windows или обратитесь к системному администратору Windows.

  • Включите сервер Lotus Domino и убедитесь в том, что задача http server запущена.

    В консоли сервера должно появиться следующее сообщение:

    DSAPI Operating System Authentication Filter Loaded successfully.
  • Запустите Web-браузер на любом сервере Domino или другом компьютере.
  • Введите URL <Domino-server>/<Domino-server-database>, чтобы открыть базу данных через Web, где <Domino-server> – имя сервера Domino (также можно использовать IP-адрес), а <Domino-server-database> – имя базы данных.

    Например: dserver/dsdatabase.nsf

  • На экране Enter Network Password (Ввод сетевого пароля) введите имя и пароль пользователя, заданные в учетной записи операционной системы.
  • Если сервер Domino запущен в системе Windows NT/2000, следует ввести имя пользователя следующим образом:
    <operating-system-user-name>@<operating-system-domain>

    Например: jdoe@os_domain

  • Если сервер Domino запущен в системе UNIX, имя пользователя вводится следующим образом:
    <operating-system-user-name>

    Например: jdoe

  • Нажмите OK для выполнения аутентификации.
  • Должно появиться содержимое базы данных.
  • Пример исходного кода

    В последующих трех примерах приведен исходный код для примера DSAPI-фильтра.

    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: SECDOM.C (основная программа)
    618 Приложение B
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание
    библиотеки, выполняющей аутентификацию пользователя Domino
    через Web с использованием учетной записи пользователя в операционной 
    системе через DSAPI.
    ******************************************************************/
    /* Включаемые файлы ввода-вывода */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* Включаемые файлы Notes SDK */
    #include "global.h"
    #include "osmem.h"
    #include "lookup.h"
    #include "dsapi.h"
    #include "addin.h"
    #define MAX_BUF_LEN 512
    #define USER_DOMAIN_SEPARATOR "@"
    /*---
    * прототипы локальных процедур
    */
    /* Точка входа общей библиотеки Notes SDK для Unix */
    STATUS FAR PASCAL MainEntryPoint (void);
    /* Процедуры с синтаксисом, требуемым интерфейсом DSAPI */
    unsigned int Authenticate(FilterContext* context, FilterAuthenticate*
    authData);
    /* Извлечение имен из адресной книги Notes */
    int getUserNames (FilterContext* context,
    char *userName,
    char **pUserFullName,
    int *pUserFullNameLen,
    char **pUserShortName,
    int *pUserShortNameLen);
    int getLookupInfo (FilterContext* context,
    char *pMatch,
    unsigned short itemNumber,
    char **pInfo,
    int *pInfoLen);
    int doAuthenticate(char *userName, char *domain, char *password);
    #ifdef UNIX
    int unixAuthenticate(char *userName, char *password);
    #else
    int separateUsernameAndDomainname(char *userName,char *separator,char
    **user,char**domain);
    int winAuthenticate(char *userName, char *domain, char *password);
    #endif
    /*---
    * далее приведены локальные процедуры
    */
    STATUS FAR PASCAL MainEntryPoint (void)
    {/
    *
    * Описание: Обеспечение основной точки входа Notes API для
    * инициализации в этой общей библиотеке. Нам нужна эта точка входа,
    * потому что мы хотим иметь возможность просматривать информацию
    * пользователей в адресной книге через
    * Notes SDK API.
    **
    Ввод: нет
    * Вывод: нет
    * Возврат: NOERROR
    */
    return NOERROR;
    }/
    *---
    * инициализация фильтра
    */
    unsigned int FilterInit(FilterInitData* filterInitData)
    {/
    *
    * Описание: Инициализация фильтра выполняется при динамической загрузке
    * общей библиотеки файльтра.
    **
    Ввод: спецификация filterInitData dsapi контролирует формат
    * данных
    * Вывод: заполняются некоторые поля filterInitData
    **
    Возврат: kFilterHandledEvent
    */
    printf("\nFilterInitData() is getting called.\n");
    /*Обязательно*/
    filterInitData->appFilterVersion = kInterfaceVersion;
    /* Измените следующий код, установив требуемые флаги */
    filterInitData->eventFlags = kFilterAuthenticate;
    /* Задайте короткое описание своего фильтра */
    strcpy(filterInitData->filterDesc,
    "Operating System Authentication Filter");
    /* здесь можно вставить код глобальной инициализации... */
    /* Выходные данные, направляемые в stdout и stderr, выводятся в
    * консоли сервера, но не записываются в файл журнала сервера.
    */
    printf("\nDSAPI Authentication filter initialized\n");
    return kFilterHandledEvent;
    }/
    *---
    * завершение работы фильтра
    */
    unsigned int TerminateFilter(unsigned int reserved)
    {/
    *
    * Описание: Завершение работы фильтра выполняется при выгрузке
    * общей библиотеки фильтра.
    **
    Ввод: зарезервирован, не используется (спецификация dsapi контролирует
    * формат данных)
    * Вывод: нет
    **
    Возврат: kFilterHandledEvent
    */
    /* здесь можно вставить код глобальной очистки... */
    return kFilterHandledEvent;
    }/
    *---
    * обработка уведомлений фильтра
    */
    unsigned int HttpFilterProc(FilterContext* context,
    unsigned int eventType, void* eventData)
    {/
    *
    * Описание: Эта процедура вызывается для обработки всех событий
    dsapi-фильтра.
    **
    Ввод: зарезервирован, не используется (спецификация dsapi контролирует
    * формат данных)
    * Вывод: нет
    **
    Возврат: kFilterNotHandled для всех ненастроенных событий,
    * в противном случае позволяет процедуре фильтра задать возвращаемое * значение.
    */
    /* Нужно включить только те события, которые требуется обрабатывать
    */
    switch (eventType) {
    case kFilterAuthenticate:
    return Authenticate(context, (FilterAuthenticate *)eventData);
    default:
    break;
    }r
    eturn kFilterNotHandled;
    }/
    *---
    * обработка аутентификации пользователей
    */
    unsigned int Authenticate(FilterContext* context,
    FilterAuthenticate* authData)
    {/
    *
    * Описание: Эта процедура вызывается при возникновении
    * события dsapi kFilterAuthUser.
    **
    Ввод: контекстная спецификация dsapi контролирует формат данных
    **
    поле пароля authData содержит пароль, предназначенный для использования
    * при аутентификации
    * поле userName содержит имя
    * для аутентификации
    * поле foundInCache = TRUE, если
    * пользователь был найден в кeше и можно провести
    * его аутентификацию.
    **
    Вывод: в поле authType authName вводится отличительное имя
    * пользователя
    * в поле authType filed вводится
    * kNotAuthentic - если нельзя выполнить аутентификацию пользователя
    * kAuthenticBasic - если можно выполнить аутентификацию
    * пользователя.
    **
    Возврат: kFilterNotHandled - если входные данные непонятны,
    * или если пользователь был найден в кeше, или
    * если обнаружилось, что аутентифицируемый пользователь
    * не задан в операционной системе.
    * kFilterHandledEvent - если пользователь задан в операционной
    системе.
    */
    /* Если пользователь найден в кeше, выполнение дополнительных действий * не требуется.
    */
    if (!authData || authData->foundInCache) {
    AddInLogMessageText ("\n user is found in the cache \n", NOERROR);
    return kFilterNotHandled;
    }/
    * Попытка проверить пароль пользователя.
    */
    if (authData->userName  authData->password) {
    char *fullName = NULL;
    int fullNameLen = 0;
    char *shortName = NULL;
    int shortNameLen = 0;
    char *user = NULL;
    char *domain = NULL;
    #if defined SOLARIS || AIX
    user=(char*)authData->userName;
    #else
    separateUsernameAndDomainname(authData->userName,USER_DOMAIN_SEPARA
    TOR,user,domain);
    #endif
    /* Просмотр пользователя в адресной книге. Получение
    * короткого имени пользователя (ожидается, что оно соответствует
    * имени пользователя в ОС) и получение полного имени пользователя
    * (ожидается, что оно будет иметь формат, подлежащий передаче обратно в * dsapi).
    */
    if (NOERROR == getUserNames (context,
    user,
    fullName,
    fullNameLen,
    shortName,
    shortNameLen) )
    {/
    * Аутентификация имени пользователя/пароля в ОС */
    if (NOERROR != doAuthenticate(shortName, domain,
    Пример программы DSAPI 623
    (char *)authData->password))
    {r
    eturn kFilterNotHandled;
    }e
    lse
    {/
    * Копирование канонического имени этого пользователя,
    * требуемого dsapi. */
    strncpy ((char *)authData->authName, fullName,
    authData->authNameSize);
    authData->authType = kAuthenticBasic;
    authData->foundInCache = TRUE;
    }r
    eturn kFilterHandledEvent;
    }}r
    eturn kFilterNotHandled;
    }i
    nt getUserNames (FilterContext* context,
    char *userName,
    char **pUserFullName,
    int *pUserFullNameLen,
    char **pUserShortName,
    int *pUserShortNameLen) {
    /*
    * Описание: Просмотр пользователя и возврат полного и короткого
    * имени пользователя.
    **
    Ввод: context - контекст, используемый для выделения памяти
    * userName - имя пользователя, для которого выполняется просмотр
    * Вывод: pUserFullName - расположение полного имени пользователя
    * pUserFullNameLen - расположение для хранения длины полного имени
    * pUserShortName – расположение короткого имени пользователя
    * pUserShortNameLen - расположение для хранения длины короткого
    имени
    **
    Возврат: -1 - ошибка, 0 - успех
    */
    STATUS error = NOERROR;
    HANDLE hLookup = NULLHANDLE;
    DWORD Matches = 0;
    char *pLookup;
    char *pName = NULL;
    char *pMatch = NULL;
    int rc = -1;
    /* Инициализация вывода */
    *pUserFullName = NULL;
    *pUserFullNameLen = 0;
    *pUserShortName = NULL;
    *pUserShortNameLen = 0;
    /* do the name lookup
    */
    error = NAMELookup2(NULL, /* NULL означает локальный просмотр */
    0, /* флаги */
    1, /* количество пространств имен */
    "$Users", /* список пространств имен */
    1, /* количество имен, для которых требуется выполнить просмотр */
    userName, /* список имен, для которых требуется выполнить просмотр */
    2, /* количество возвращаемых элементов */
    "FullName\0ShortName", /* список возвращаемых
    * элементов */
    hLookup); /* место для получения дескриптора
    * буфера возврата */
    if (error || (NULLHANDLE == hLookup))
    goto NoUnlockExit;
    pLookup = (char *) OSLockObject(hLookup);
    /* Получение указателя нашей записи.
    */
    pName = (char *)NAMELocateNextName2(pLookup, /* буфер просмотра
    * имени */
    NULL, /* начинать в начале
    * буфера просмотра */
    Matches); /* Получает количество
    * найденных записей
    * (должно быть равно 1) */
    /* Если запись не найдена - выход */
    if ((pName == NULL) || (Matches <= 0)) {
    goto Exit;
    }p
    Match = (char *)NAMELocateNextMatch2(pLookup, /* буфер просмотра
    * имени */
    pName, /* найденная нами запись */
    NULL); /* предыдущих соответствий нет */
    if (NULL == pMatch) {
    goto Exit;
    }
    /* Извлечение полного имени из полученной информации */
    if ( getLookupInfo (context,
    pMatch,
    0,
    pUserFullName,
    pUserFullNameLen) )
    goto Exit;
    AddInLogMessageText ("full name=%s,length=%d\n", 0,*pUserFullName,*
    pUserFullNameLen);
    /* Извлечение короткого имени из полученной информации */
    if ( getLookupInfo (context,
    pMatch,
    1,
    pUserShortName,
    pUserShortNameLen) )
    goto Exit;
    else
    rc = 0;
    AddInLogMessageText ("short name=%s,length=%d\n", 0,*pUserShortName
    ,*pUserShortNameLen);
    Exit:
    if ( pLookup  hLookup )
    OSUnlock(hLookup);
    NoUnlockExit:
    if (NULLHANDLE != hLookup)
    OSMemFree(hLookup);
    return rc;
    }i
    nt getLookupInfo (FilterContext* context,
    char *pMatch,
    unsigned short itemNumber,
    char **pInfo,
    int *pInfoLen) {
    /*
    * Описание: Извлечение информации из буфера просмотра
    *
    * Ввод: context - контекст, используемый для выделения памяти
    * pMatch – имя буфера просмотра
    * itemNumber – место хранения информации в буфере просмотра
    * Вывод: pInfo – расположение буфера информации
    * pInfoLen – место хранения длины информации
    *
    * Возврат: -1 - ошибка, 0 - успех
    */
    unsigned int reserved = 0;
    unsigned int errID;
    char *ValuePtr = NULL;
    WORD ValueLength, DataType;
    STATUS error;
    void *newSpace = NULL;
    /* Инициализация вывода */
    *pInfo = NULL;
    *pInfoLen = 0;
    /* Проверка типа и длины информации */
    ValuePtr = (char *)NAMELocateItem2(pMatch,
    itemNumber,
    DataType,
    ValueLength);
    if (NULL == ValuePtr || ValueLength == 0) {
    return -1;
    }V
    alueLength -= sizeof(WORD);
    /* проверка значения DataType */
    switch (DataType) {
    case TYPE_TEXT_LIST:
    break;
    case TYPE_TEXT:
    break;
    default:
    return -1;
    }/
    * Выделение пространства для информации. Эта память освобождается
    * автоматически при завершении работы потока.
    */
    newSpace = (context->AllocMem)(context, ValueLength+1,
    reserved, errID);
    *pInfo = (char *) newSpace;
    if (NULL == *pInfo) {
    printf ("Out of memory\n");
    return -1;
    }/
    * Получение информации */
    error = NAMEGetTextItem2(pMatch, /* найденное соответствие */
    itemNumber, /* номер элемента в порядке
    * просмотра элементов */
    0, /* Номер элемента в текстовых
    * списках */
    *pInfo, /* буфер для копирования
    * результата */
    MAX_BUF_LEN); /* Длина буфера */
    if (!error) {
    *pInfoLen = strlen(*pInfo)+1;
    return 0;
    }r
    eturn -1;
    }
    int doAuthenticate(char *userName, char *domain, char *password) {
    /*
    * Описание: Проверяет, существует ли пользователь в операционной системе
    * Если существует, определяет, можно ли проверить пароль.
    **
    Ввод: userName - имя пользователя
    * domain - имя домена (NULL - UNIX)
    * password - пароль
    **
    Возврат: -1 - ошибка, 0 - успех
    */
    if (!userName) {
    AddInLogMessageText ("\nERROR: User must be specified\n", NOERROR);
    return -1;
    }#
    if defined SOLARIS || AIX
    printf("\nin doAuthenticate()\n");
    return(unixAuthenticate(userName, password));
    #else
    if (!domain) {
    AddInLogMessageText ("\nERROR: Domain must be specified. Use username@
    domainname format\n",
    NOERROR);
    return -1;
    }r
    eturn(winAuthenticate(userName, domain, password));
    #endif
    }/
    * ----- конец secdom.c */
    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: W_SECDOM.C (код для Windows)
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание
    библиотеки, выполняющей аутентификацию пользователя Domino
    через Web с использованием учетной записи пользователя в операционной 
    системе через DSAPI.
    ******************************************************************/
    /* Включаемые файлы W32 */
    #include <windows.h>
    #include <winbase.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* ************************************************************* */
    /* * Windows API для аутентификации ОС. * */
    /* ************************************************************* */
    int separateUsernameAndDomainname(char *userName,char *separator,
    char **user, char **domain)
    {*
    user=strtok(userName,separator);
    *domain=strtok(NULL,separator);
    return 0;
    }/
    * ************************************************************* */
    /* * Windows API для аутентификации ОС. * */
    /* ************************************************************* */
    int winAuthenticate(char *userName, char *domain, char *password)
    {c
    har *lpMsgBuf;
    HANDLE phToken;
    printf("\n Executing Windows-specific authentication for user %s
    in domain
    %s\n",userName,domain);
    if (LogonUser(userName,domain,password,LOGON32_LOGON_NETWORK,
    LOGON32_PROVIDER_DEFAULT,phToken))
    {p
    rintf(" ** Successful return from Windows-specific authentication
    \n");
    return NOERROR;
    }e
    lse
    {F
    ormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) lpMsgBuf,
    0,
    NULL);
    printf("***** Error from Windows-specific authentication: ***\n");
    printf(" %s\n",lpMsgBuf);
    LocalFree(lpMsgBuf);
    return -1;
    }}
    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: U_SECDOM.C (код для UNIX)
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание библиотеки, 
    выполняющей аутентификацию пользователя Domino через Web
    с использованием учетной записи пользователя в операционной системе
    через DSAPI.
    ******************************************************************/
    /* Включаемые файлы для ввода и вывода */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* Включаемые файлы для аутентификации в UNIX */
    #ifdef SOLARIS
    #include <shadow.h>
    #endif
    #ifdef AIX
    #include <sys/types.h>
    #include <pwd.h>
    #endif
    int unixAuthenticate(char *userName, char *password)
    {c
    har buffer[1024];
    int error = -1;
    int success = 0;
    int unknown = 1;
    /* Получение UNIX-записи для данного пользователя */
    #ifdef SOLARIS
    struct spwd result;
    #endif
    #ifdef AIX
    struct passwd *result;
    #endif
    /* Получение UNIX-записи для данного пользователя */
    #ifdef SOLARIS
    if (getspnam_r(userName, result, buffer, sizeof(buffer))) {
    /* Шифрование пароля и проверка его соответствия
    * зашифрованному паролю в записи пользователя.
    */
    char *thisCrypt = NULL;
    thisCrypt = (char *)crypt(password, result.sp_pwdp);
    if (strcmp (result.sp_pwdp, thisCrypt) == 0) {
    return success;
    } else {
    return error;
    }}#
    endif
    #ifdef AIX
    result = getpwnam(userName);
    if (result  result->pw_passwd) {
    /* Шифрование пароля и проверка его соответствия
    * зашифрованному паролю в записи пользователя.
    */
    char *thisCrypt = NULL;
    thisCrypt = (char *)crypt(password,
    result->pw_passwd);
    if (strcmp (result->pw_passwd, thisCrypt) == 0) {
    return success;
    } else {
    return error;
    }}#
    endif
    return unknown;
    }
    Страницы:

    Это приложение содержит пример DSAPI-программы, иллюстрирующий аутентификацию Web-пользователя Domino через учетную запись пользователя в операционной системе. Этот пример реализует метод обеспечения единой регистрации на основе DSAPI, описанный в лекции 7, "Принцип единого входа".

    В целом эта DSAPI-программа содержит код для использования идентификатора и пароля пользователя в Windows-сети пользователя при запуске фильтра на сервере Domino на основе Windows. При запуске на сервере Domino на основе UNIX, применяется идентификатор и пароль пользователя в системе UNIX.

    Пример содержит три файла: основная программа, код для Windows и код для UNIX. Полный исходный код, make-файлы и файлы определений представлены в пакете инструментов Domino 6 C API в папке Samples, в подпапке Admin.

    Настройка среды

  • Для использования этого DSAPI-фильтра он должен быть зарегистрирован на сервере Domino в соответствии с описанием, приведенным в разделе "Регистрация DSAPI-фильтра в Domino".
  • Пользователь, выполняющий тестирование этой программы, должен иметь учетную запись пользователя Domino на этом сервере Domino, а также учетную запись пользователя в операционной системе на компьютере, на котором запущен сервер. Сведения о создании учетной записи пользователя Domino для существующей учетной записи пользователя в операционной системе см. в разделе "Создание учетной записи пользователя Domino для существующего пользователя операционной системы".
  • Для тестирования этой программы попробуйте открыть базу данных на сервере Domino из Web-браузера. Убедитесь в корректности настройки ACL этой базы данных. Для удобства установите уровень доступа Reader (Читатель) для учетной записи Default и уровень доступа No Access (Нет доступа) для учетной записи Anonymous (Аноним). Установка уровня доступа No Access для учетной записи Anonymous (Аноним) вызывает принудительную аутентификацию.
  • Регистрация DSAPI-фильтра в Domino

  • Скомпилируйте пример программы и скопируйте DLL в программный каталог сервера Domino.
  • Запустите сервер Domino.
  • Из Notes UI откройте базу данных каталога сервера Lotus Domino (базу данных names.nsf).
  • В представлении Server (Сервер) > Servers (Серверы) откройте документ Server данного сервера.
  • На вкладке Internet Protocols (интернет-протоколы) введите имя DLL в поле имен файлов DSAPI-фильтров.
  • Сохраните документ.
  • Создание учетной записи пользователя Domino для существующего пользователя операционной системы

  • Запустите сервер Domino.
  • Запустите Domino Administrator.
  • Убедитесь в том, что поле Server (Сервер) указывает на сервер, а не на Local. Если оно указывает на Local, измените это значение в меню File (Файл) – Open Server (Открыть сервер) таким образом, чтобы оно указывало на сервер Domino.
  • Выделите представление People (Люди) на левой панели.
  • В выпадающем меню People (Люди) на правой панели выберите действие Register (Регистрация).
  • Введите значения в поля First name (Имя), Last name (Фамилия), Short name (Короткое имя) и Password (Пароль). Короткое имя должно совпадать с именем пользователя в учетной записи операционной системы.
  • Нажмите кнопку Register (Регистрация) для создания пользователя Domino.
  • Закройте Domino Administrator.
  • Обновите или отключите сервер Domino.
  • Запуск примера DSAPI-программы secdom

    Примечание (только для серверов Windows). Для аутентификации с использованием DSAPI-фильтра в Windows, для пользователя операционной системы должна быть включена политика безопасности пользователя Act as part of the operating system (Работа в режиме операционной системы). Если определены политики уровня домена, они также должны назначать пользователю это право.

    Если для пользователя Windows не установлена эта политика безопасности, аутентификация будет неуспешной и в консоль сервера будет выведена ошибка.

    Чтобы назначить политику безопасности пользователя Windows для определенного пользователя, просмотрите документацию Windows или обратитесь к системному администратору Windows.

  • Включите сервер Lotus Domino и убедитесь в том, что задача http server запущена.

    В консоли сервера должно появиться следующее сообщение:

    DSAPI Operating System Authentication Filter Loaded successfully.
  • Запустите Web-браузер на любом сервере Domino или другом компьютере.
  • Введите URL <Domino-server>/<Domino-server-database>, чтобы открыть базу данных через Web, где <Domino-server> – имя сервера Domino (также можно использовать IP-адрес), а <Domino-server-database> – имя базы данных.

    Например: dserver/dsdatabase.nsf

  • На экране Enter Network Password (Ввод сетевого пароля) введите имя и пароль пользователя, заданные в учетной записи операционной системы.
  • Если сервер Domino запущен в системе Windows NT/2000, следует ввести имя пользователя следующим образом:
    <operating-system-user-name>@<operating-system-domain>

    Например: jdoe@os_domain

  • Если сервер Domino запущен в системе UNIX, имя пользователя вводится следующим образом:
    <operating-system-user-name>

    Например: jdoe

  • Нажмите OK для выполнения аутентификации.
  • Должно появиться содержимое базы данных.
  • Пример исходного кода

    В последующих трех примерах приведен исходный код для примера DSAPI-фильтра.

    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: SECDOM.C (основная программа)
    618 Приложение B
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание
    библиотеки, выполняющей аутентификацию пользователя Domino
    через Web с использованием учетной записи пользователя в операционной 
    системе через DSAPI.
    ******************************************************************/
    /* Включаемые файлы ввода-вывода */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* Включаемые файлы Notes SDK */
    #include "global.h"
    #include "osmem.h"
    #include "lookup.h"
    #include "dsapi.h"
    #include "addin.h"
    #define MAX_BUF_LEN 512
    #define USER_DOMAIN_SEPARATOR "@"
    /*---
    * прототипы локальных процедур
    */
    /* Точка входа общей библиотеки Notes SDK для Unix */
    STATUS FAR PASCAL MainEntryPoint (void);
    /* Процедуры с синтаксисом, требуемым интерфейсом DSAPI */
    unsigned int Authenticate(FilterContext* context, FilterAuthenticate*
    authData);
    /* Извлечение имен из адресной книги Notes */
    int getUserNames (FilterContext* context,
    char *userName,
    char **pUserFullName,
    int *pUserFullNameLen,
    char **pUserShortName,
    int *pUserShortNameLen);
    int getLookupInfo (FilterContext* context,
    char *pMatch,
    unsigned short itemNumber,
    char **pInfo,
    int *pInfoLen);
    int doAuthenticate(char *userName, char *domain, char *password);
    #ifdef UNIX
    int unixAuthenticate(char *userName, char *password);
    #else
    int separateUsernameAndDomainname(char *userName,char *separator,char
    **user,char**domain);
    int winAuthenticate(char *userName, char *domain, char *password);
    #endif
    /*---
    * далее приведены локальные процедуры
    */
    STATUS FAR PASCAL MainEntryPoint (void)
    {/
    *
    * Описание: Обеспечение основной точки входа Notes API для
    * инициализации в этой общей библиотеке. Нам нужна эта точка входа,
    * потому что мы хотим иметь возможность просматривать информацию
    * пользователей в адресной книге через
    * Notes SDK API.
    **
    Ввод: нет
    * Вывод: нет
    * Возврат: NOERROR
    */
    return NOERROR;
    }/
    *---
    * инициализация фильтра
    */
    unsigned int FilterInit(FilterInitData* filterInitData)
    {/
    *
    * Описание: Инициализация фильтра выполняется при динамической загрузке
    * общей библиотеки файльтра.
    **
    Ввод: спецификация filterInitData dsapi контролирует формат
    * данных
    * Вывод: заполняются некоторые поля filterInitData
    **
    Возврат: kFilterHandledEvent
    */
    printf("\nFilterInitData() is getting called.\n");
    /*Обязательно*/
    filterInitData->appFilterVersion = kInterfaceVersion;
    /* Измените следующий код, установив требуемые флаги */
    filterInitData->eventFlags = kFilterAuthenticate;
    /* Задайте короткое описание своего фильтра */
    strcpy(filterInitData->filterDesc,
    "Operating System Authentication Filter");
    /* здесь можно вставить код глобальной инициализации... */
    /* Выходные данные, направляемые в stdout и stderr, выводятся в
    * консоли сервера, но не записываются в файл журнала сервера.
    */
    printf("\nDSAPI Authentication filter initialized\n");
    return kFilterHandledEvent;
    }/
    *---
    * завершение работы фильтра
    */
    unsigned int TerminateFilter(unsigned int reserved)
    {/
    *
    * Описание: Завершение работы фильтра выполняется при выгрузке
    * общей библиотеки фильтра.
    **
    Ввод: зарезервирован, не используется (спецификация dsapi контролирует
    * формат данных)
    * Вывод: нет
    **
    Возврат: kFilterHandledEvent
    */
    /* здесь можно вставить код глобальной очистки... */
    return kFilterHandledEvent;
    }/
    *---
    * обработка уведомлений фильтра
    */
    unsigned int HttpFilterProc(FilterContext* context,
    unsigned int eventType, void* eventData)
    {/
    *
    * Описание: Эта процедура вызывается для обработки всех событий
    dsapi-фильтра.
    **
    Ввод: зарезервирован, не используется (спецификация dsapi контролирует
    * формат данных)
    * Вывод: нет
    **
    Возврат: kFilterNotHandled для всех ненастроенных событий,
    * в противном случае позволяет процедуре фильтра задать возвращаемое * значение.
    */
    /* Нужно включить только те события, которые требуется обрабатывать
    */
    switch (eventType) {
    case kFilterAuthenticate:
    return Authenticate(context, (FilterAuthenticate *)eventData);
    default:
    break;
    }r
    eturn kFilterNotHandled;
    }/
    *---
    * обработка аутентификации пользователей
    */
    unsigned int Authenticate(FilterContext* context,
    FilterAuthenticate* authData)
    {/
    *
    * Описание: Эта процедура вызывается при возникновении
    * события dsapi kFilterAuthUser.
    **
    Ввод: контекстная спецификация dsapi контролирует формат данных
    **
    поле пароля authData содержит пароль, предназначенный для использования
    * при аутентификации
    * поле userName содержит имя
    * для аутентификации
    * поле foundInCache = TRUE, если
    * пользователь был найден в кeше и можно провести
    * его аутентификацию.
    **
    Вывод: в поле authType authName вводится отличительное имя
    * пользователя
    * в поле authType filed вводится
    * kNotAuthentic - если нельзя выполнить аутентификацию пользователя
    * kAuthenticBasic - если можно выполнить аутентификацию
    * пользователя.
    **
    Возврат: kFilterNotHandled - если входные данные непонятны,
    * или если пользователь был найден в кeше, или
    * если обнаружилось, что аутентифицируемый пользователь
    * не задан в операционной системе.
    * kFilterHandledEvent - если пользователь задан в операционной
    системе.
    */
    /* Если пользователь найден в кeше, выполнение дополнительных действий * не требуется.
    */
    if (!authData || authData->foundInCache) {
    AddInLogMessageText ("\n user is found in the cache \n", NOERROR);
    return kFilterNotHandled;
    }/
    * Попытка проверить пароль пользователя.
    */
    if (authData->userName  authData->password) {
    char *fullName = NULL;
    int fullNameLen = 0;
    char *shortName = NULL;
    int shortNameLen = 0;
    char *user = NULL;
    char *domain = NULL;
    #if defined SOLARIS || AIX
    user=(char*)authData->userName;
    #else
    separateUsernameAndDomainname(authData->userName,USER_DOMAIN_SEPARA
    TOR,user,domain);
    #endif
    /* Просмотр пользователя в адресной книге. Получение
    * короткого имени пользователя (ожидается, что оно соответствует
    * имени пользователя в ОС) и получение полного имени пользователя
    * (ожидается, что оно будет иметь формат, подлежащий передаче обратно в * dsapi).
    */
    if (NOERROR == getUserNames (context,
    user,
    fullName,
    fullNameLen,
    shortName,
    shortNameLen) )
    {/
    * Аутентификация имени пользователя/пароля в ОС */
    if (NOERROR != doAuthenticate(shortName, domain,
    Пример программы DSAPI 623
    (char *)authData->password))
    {r
    eturn kFilterNotHandled;
    }e
    lse
    {/
    * Копирование канонического имени этого пользователя,
    * требуемого dsapi. */
    strncpy ((char *)authData->authName, fullName,
    authData->authNameSize);
    authData->authType = kAuthenticBasic;
    authData->foundInCache = TRUE;
    }r
    eturn kFilterHandledEvent;
    }}r
    eturn kFilterNotHandled;
    }i
    nt getUserNames (FilterContext* context,
    char *userName,
    char **pUserFullName,
    int *pUserFullNameLen,
    char **pUserShortName,
    int *pUserShortNameLen) {
    /*
    * Описание: Просмотр пользователя и возврат полного и короткого
    * имени пользователя.
    **
    Ввод: context - контекст, используемый для выделения памяти
    * userName - имя пользователя, для которого выполняется просмотр
    * Вывод: pUserFullName - расположение полного имени пользователя
    * pUserFullNameLen - расположение для хранения длины полного имени
    * pUserShortName – расположение короткого имени пользователя
    * pUserShortNameLen - расположение для хранения длины короткого
    имени
    **
    Возврат: -1 - ошибка, 0 - успех
    */
    STATUS error = NOERROR;
    HANDLE hLookup = NULLHANDLE;
    DWORD Matches = 0;
    char *pLookup;
    char *pName = NULL;
    char *pMatch = NULL;
    int rc = -1;
    /* Инициализация вывода */
    *pUserFullName = NULL;
    *pUserFullNameLen = 0;
    *pUserShortName = NULL;
    *pUserShortNameLen = 0;
    /* do the name lookup
    */
    error = NAMELookup2(NULL, /* NULL означает локальный просмотр */
    0, /* флаги */
    1, /* количество пространств имен */
    "$Users", /* список пространств имен */
    1, /* количество имен, для которых требуется выполнить просмотр */
    userName, /* список имен, для которых требуется выполнить просмотр */
    2, /* количество возвращаемых элементов */
    "FullName\0ShortName", /* список возвращаемых
    * элементов */
    hLookup); /* место для получения дескриптора
    * буфера возврата */
    if (error || (NULLHANDLE == hLookup))
    goto NoUnlockExit;
    pLookup = (char *) OSLockObject(hLookup);
    /* Получение указателя нашей записи.
    */
    pName = (char *)NAMELocateNextName2(pLookup, /* буфер просмотра
    * имени */
    NULL, /* начинать в начале
    * буфера просмотра */
    Matches); /* Получает количество
    * найденных записей
    * (должно быть равно 1) */
    /* Если запись не найдена - выход */
    if ((pName == NULL) || (Matches <= 0)) {
    goto Exit;
    }p
    Match = (char *)NAMELocateNextMatch2(pLookup, /* буфер просмотра
    * имени */
    pName, /* найденная нами запись */
    NULL); /* предыдущих соответствий нет */
    if (NULL == pMatch) {
    goto Exit;
    }
    /* Извлечение полного имени из полученной информации */
    if ( getLookupInfo (context,
    pMatch,
    0,
    pUserFullName,
    pUserFullNameLen) )
    goto Exit;
    AddInLogMessageText ("full name=%s,length=%d\n", 0,*pUserFullName,*
    pUserFullNameLen);
    /* Извлечение короткого имени из полученной информации */
    if ( getLookupInfo (context,
    pMatch,
    1,
    pUserShortName,
    pUserShortNameLen) )
    goto Exit;
    else
    rc = 0;
    AddInLogMessageText ("short name=%s,length=%d\n", 0,*pUserShortName
    ,*pUserShortNameLen);
    Exit:
    if ( pLookup  hLookup )
    OSUnlock(hLookup);
    NoUnlockExit:
    if (NULLHANDLE != hLookup)
    OSMemFree(hLookup);
    return rc;
    }i
    nt getLookupInfo (FilterContext* context,
    char *pMatch,
    unsigned short itemNumber,
    char **pInfo,
    int *pInfoLen) {
    /*
    * Описание: Извлечение информации из буфера просмотра
    *
    * Ввод: context - контекст, используемый для выделения памяти
    * pMatch – имя буфера просмотра
    * itemNumber – место хранения информации в буфере просмотра
    * Вывод: pInfo – расположение буфера информации
    * pInfoLen – место хранения длины информации
    *
    * Возврат: -1 - ошибка, 0 - успех
    */
    unsigned int reserved = 0;
    unsigned int errID;
    char *ValuePtr = NULL;
    WORD ValueLength, DataType;
    STATUS error;
    void *newSpace = NULL;
    /* Инициализация вывода */
    *pInfo = NULL;
    *pInfoLen = 0;
    /* Проверка типа и длины информации */
    ValuePtr = (char *)NAMELocateItem2(pMatch,
    itemNumber,
    DataType,
    ValueLength);
    if (NULL == ValuePtr || ValueLength == 0) {
    return -1;
    }V
    alueLength -= sizeof(WORD);
    /* проверка значения DataType */
    switch (DataType) {
    case TYPE_TEXT_LIST:
    break;
    case TYPE_TEXT:
    break;
    default:
    return -1;
    }/
    * Выделение пространства для информации. Эта память освобождается
    * автоматически при завершении работы потока.
    */
    newSpace = (context->AllocMem)(context, ValueLength+1,
    reserved, errID);
    *pInfo = (char *) newSpace;
    if (NULL == *pInfo) {
    printf ("Out of memory\n");
    return -1;
    }/
    * Получение информации */
    error = NAMEGetTextItem2(pMatch, /* найденное соответствие */
    itemNumber, /* номер элемента в порядке
    * просмотра элементов */
    0, /* Номер элемента в текстовых
    * списках */
    *pInfo, /* буфер для копирования
    * результата */
    MAX_BUF_LEN); /* Длина буфера */
    if (!error) {
    *pInfoLen = strlen(*pInfo)+1;
    return 0;
    }r
    eturn -1;
    }
    int doAuthenticate(char *userName, char *domain, char *password) {
    /*
    * Описание: Проверяет, существует ли пользователь в операционной системе
    * Если существует, определяет, можно ли проверить пароль.
    **
    Ввод: userName - имя пользователя
    * domain - имя домена (NULL - UNIX)
    * password - пароль
    **
    Возврат: -1 - ошибка, 0 - успех
    */
    if (!userName) {
    AddInLogMessageText ("\nERROR: User must be specified\n", NOERROR);
    return -1;
    }#
    if defined SOLARIS || AIX
    printf("\nin doAuthenticate()\n");
    return(unixAuthenticate(userName, password));
    #else
    if (!domain) {
    AddInLogMessageText ("\nERROR: Domain must be specified. Use username@
    domainname format\n",
    NOERROR);
    return -1;
    }r
    eturn(winAuthenticate(userName, domain, password));
    #endif
    }/
    * ----- конец secdom.c */
    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: W_SECDOM.C (код для Windows)
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание
    библиотеки, выполняющей аутентификацию пользователя Domino
    через Web с использованием учетной записи пользователя в операционной 
    системе через DSAPI.
    ******************************************************************/
    /* Включаемые файлы W32 */
    #include <windows.h>
    #include <winbase.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* ************************************************************* */
    /* * Windows API для аутентификации ОС. * */
    /* ************************************************************* */
    int separateUsernameAndDomainname(char *userName,char *separator,
    char **user, char **domain)
    {*
    user=strtok(userName,separator);
    *domain=strtok(NULL,separator);
    return 0;
    }/
    * ************************************************************* */
    /* * Windows API для аутентификации ОС. * */
    /* ************************************************************* */
    int winAuthenticate(char *userName, char *domain, char *password)
    {c
    har *lpMsgBuf;
    HANDLE phToken;
    printf("\n Executing Windows-specific authentication for user %s
    in domain
    %s\n",userName,domain);
    if (LogonUser(userName,domain,password,LOGON32_LOGON_NETWORK,
    LOGON32_PROVIDER_DEFAULT,phToken))
    {p
    rintf(" ** Successful return from Windows-specific authentication
    \n");
    return NOERROR;
    }e
    lse
    {F
    ormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
    FORMAT_MESSAGE_FROM_SYSTEM,
    NULL,
    GetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR) lpMsgBuf,
    0,
    NULL);
    printf("***** Error from Windows-specific authentication: ***\n");
    printf(" %s\n",lpMsgBuf);
    LocalFree(lpMsgBuf);
    return -1;
    }}
    /******************************************************************
    ПРОГРАММА: SECDOM
    ФАЙЛ: U_SECDOM.C (код для UNIX)
    НАЗНАЧЕНИЕ: Пример программы C API, демонстрирующей создание библиотеки, 
    выполняющей аутентификацию пользователя Domino через Web
    с использованием учетной записи пользователя в операционной системе
    через DSAPI.
    ******************************************************************/
    /* Включаемые файлы для ввода и вывода */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    /* Включаемые файлы для аутентификации в UNIX */
    #ifdef SOLARIS
    #include <shadow.h>
    #endif
    #ifdef AIX
    #include <sys/types.h>
    #include <pwd.h>
    #endif
    int unixAuthenticate(char *userName, char *password)
    {c
    har buffer[1024];
    int error = -1;
    int success = 0;
    int unknown = 1;
    /* Получение UNIX-записи для данного пользователя */
    #ifdef SOLARIS
    struct spwd result;
    #endif
    #ifdef AIX
    struct passwd *result;
    #endif
    /* Получение UNIX-записи для данного пользователя */
    #ifdef SOLARIS
    if (getspnam_r(userName, result, buffer, sizeof(buffer))) {
    /* Шифрование пароля и проверка его соответствия
    * зашифрованному паролю в записи пользователя.
    */
    char *thisCrypt = NULL;
    thisCrypt = (char *)crypt(password, result.sp_pwdp);
    if (strcmp (result.sp_pwdp, thisCrypt) == 0) {
    return success;
    } else {
    return error;
    }}#
    endif
    #ifdef AIX
    result = getpwnam(userName);
    if (result  result->pw_passwd) {
    /* Шифрование пароля и проверка его соответствия
    * зашифрованному паролю в записи пользователя.
    */
    char *thisCrypt = NULL;
    thisCrypt = (char *)crypt(password,
    result->pw_passwd);
    if (strcmp (result->pw_passwd, thisCrypt) == 0) {
    return success;
    } else {
    return error;
    }}#
    endif
    return unknown;
    }
    Вернуться к учебному плану