Всё гениальное просто. Но до этой простоты нужно перечитать тысячи мануалов. Поэтому, разобравшись, мне захотелось написать quick start по тому, как сделать прозрачную авторизацию в Web-приложении для пользователя, авторизованного в AD, и поделиться своим тестовым проектом. Интересен взгляд со стороны.



Для начала немного теории. SSO, она же прозрачная авторизация, это идея, по которой пользователь раз вводит логин/пароль своей учётной записи в Active Directory при входе на компьютер, и дальше, открывая Web-приложение (не только, но речь о нём) уже автоматически авторизуется с данными своей учётки.

В браузерах для этого заложен принцип — получая в ответ на свой Get-запрос HTTP-код 401 «Not Authorized», и в HTTP-заголовках <WWW-Authenticate: Negotiate>, он, браузер, делает запрос в KDC (Key Distribution Center — одна из служб AD) на получение специального SPNEGO-токена для данного Web-сервиса. Если учётки для такого Web-сервиса нет в AD, то браузер берёт стандартный ответ для авторизации по NTLM. Но в данном случае мы считаем, что что-то пошло не так.

Итак, браузер, в случае корректных настроек данного Web-сервиса в AD, на ответ 401 вновь отправляет Get-запрос, но уже с заголовком вида <Authorization: YIIJvwYGKw… > Если токен начинается так, с «YII», значит это Kerberos-закодированный тикет, содержащий данные для авторизации.

Kerberos — это просто тип шифрования, но поскольку он в основном используется для SSO, эти понятия тесно связаны.

Далее Web-сервис, получив токен, с помощью kerberos-клиента отправляет его в KDC на проверку. И, в случае успеха, получает имя пользователя в AD. Которое дальше уже можно использовать для поиска данных о пользователе (например, групп, в которых он состоит) уже через другой сервис доступа к AD — LDAP.

Наиболее наглядно описывает этот процесс схема из официальной документации Microsoft. И, надо сказать, на удивление именно их документация дала наибольшее понимание предмета.

image
Отсюда

Таким образом, помимо создания Web-приложения, нужны следующие действия:

Что требуется сделать на стороне администраторов AD

— задать в AD SPN-имя для Web-сервиса (вида HTTP/webservice.example.com@EXAMPLE.COM). Это позволит клиентским браузерам запрашивать токен для данного сервиса и передавать его в HTTP-заголовке Web-сервису, а Kerberos-клиенту через данный сервис на основе ключа проверять подлинность пользователей,
— сформировать для этого сервиса ключ krb5.keytab, который будет использоваться в Kerberos-клиенте для проверки подлинности пользователей.

Дополнительные действия на сервере Web-сервиса

— потребуется установить Kerberos-клиент (в Windows он уже есть, в случае Linux — например, для RedHat команда для установки: yum install krb5-workstation krb5-libs krb5-auth-dialog krb5-devel);
— для него нужно будет настроить файл конфигурации krb5.conf для доступа к KDC (как — администраторы AD назовут правильные настройки, главный параметр — kdc);
— а также подложить файл ключа /etc/krb5.keytab.

В Web-приложении

— устанавливается модуль kerberos, для работы с kerberos-клиентом,
— и модуль activedirectory, для выполнения LDAP-запросов.

Один неприятный момент — для Windows модуль kerberos предоставляет отдельный API, и использовать его не вышло. Если у кого-то есть решение — это была бы неоценимая помощь.

Для Linux модуль kerberos предоставляет два основных метода, которые нужны в работе:

— authGSSServerStep — отправка токена на проверку,
— authUserKrb5Password — авторизация по логин/пароль, на случай если прозрачная авторизация не сработала.

Документации по использованию методов нет, но есть толковые комментарии в файле lib\kerberos.js.

Вот основной кусок кода, проверяющий пришедший от браузера токен:

        //cut phrase "Negotiate "
        var ticket = req.headers.authorization.substring(10);

        //init context
        kerberos.authGSSServerInit("HTTP", function(err, context) {
            //check ticket
            kerberos.authGSSServerStep(context, ticket, function(err) {
                //in success context contains username
                res.set( 'WWW-Authenticate', 'Negotiate ' + context.response);
                res.send(context.username);
            });
        });

> Ссылка на тестовый проект на GitHub

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

В результате при открытии страницы, если всё сделано верно, должно быть



Ожидаемые ограничения:

— адрес Url не может быть в виде ip:port, а только с указанием DNS-имени (связано с регистрацией Web-сервиса в AD),
— данная авторизация работает только при определённых настройках IE, но это настройки по умолчанию («Автоматический вход в сеть только в зоне интрасети», «Разрешить встроенную проверку подлинности Windows»). Chrome использует настройки IE. В остальных браузерах возможно потребуются свои настройки.
Поделиться с друзьями
-->

Комментарии (5)


  1. Iremel
    16.02.2017 15:26

    Вот интересно, а если Web-сервер в виде кластера? Реально ли на каждом из них делать проверку Kerberos-авторизации, используя один и тот же принципал — т.е. на одно виртуальное имя хоста, по которому ходят все пользователи?


    1. mayorovp
      16.02.2017 16:12

      Да. Причем можно как использовать общий ключ — так и выписывать им индивидуальные. В Линуксе — точно.


  1. streetflush
    20.02.2017 09:45

    1. sjoekle
      20.02.2017 09:46

      Спасибо. Он работает в Windows, но не поддерживает Linux.


  1. ShinRa
    20.02.2017 09:47

    Я как-то хотел на java написать небольшое приложение, которое работало бы с запросами в 1С СППР. Хотел получать в ответ JSON и брать из него только необходимую информацию, а не все то убожество что есть в самом СППР. Уперся именно в этот метод аутентификации. Так и не понял как генерировать токен для аутентификации. Где бы еще поподробней об этом почитать?