Pull to refresh

nodejs: SSO-авторизация через Kerberos

Reading time3 min
Views47K
Всё гениальное просто. Но до этой простоты нужно перечитать тысячи мануалов. Поэтому, разобравшись, мне захотелось написать 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. В остальных браузерах возможно потребуются свои настройки.
Tags:
Hubs:
Total votes 14: ↑13 and ↓1+12
Comments5

Articles