Веб авторизація доменного користувача через nginx і HTTP Negotiate

    Нещодавно постало завдання — забезпечити прозору авторизацію користувачів домену CRM, власне Microsoft давним давно розробив для цих цілей метод автентифікації HTTP Negotiate, це все чудово працює на IIS і Windows Server, а у нас за плечима Samba4 в ролі Primary Domain Controller і проксирующий веб-сервер nginx. Як бути?

    У мережі купа інформації по організації подібної схеми для Apache2 & AD на базі Windows, а ось користувачам nginx доводиться збирати по крихтах, інформації кіт наплакав. У базовій поставці Nginx немає подібного функціоналу. Благо люди не впали духом і історія почалася в мейл розсилання nginx в 2009 році, де один американський товариш з Огайо найняв розробника на RentACoder для запиливания модуля з подібним функціоналом. Хлопці форкнули подібний модуль для апача, прикрутили його до nginx і результати роботи виклали на github, де модуль час від часу допиливался різними людьми і в підсумку прийняв роботоспособный вигляд. Останню версію можна отримати на гітхабі.


У цій інструкції я розповім як змусити працювати nginx з SPNEGO модулем і samba4.


Перше необхідне — зібрати nginx з потрібним нам модулем. Для прикладу буде використовуватися Ubuntu 16.04.

Для початку ставимо nginx
apt-get install nginx -V

Далі куди-небудь качаємо останню версію исходников з офіційного сайту.
wget http://nginx.org/download/nginx-1.11.2.tar.gz

Відмінно, распакуем папку з исходниками і покладемо в нього наш spnego-http-auth-nginx-module
tar xvzf nginx-1.11.2.tar.gz
cd nginx-1.11.2
git clone https://github.com/stnoonan/spnego-http-auth-nginx-module

Дивимося з якими опціями у нас зараз зібраний nginx з базової поставки і отримуємо порятнку
root@dc1:~# nginx -V
nginx version: nginx/1.11.1
built by gcc 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2.1) 
built with OpenSSL 1.0.2 g-fips 1 Mar 2016
TLS SNI support enabled
configure arguments: --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log-http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock-http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --with-threads --with-stream --with-stream_ssl_module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-debug --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed'

Копіюємо в блокнот онучу і додаємо куди-небудь
--add-module=spnego-http-auth-nginx-module

Приступаємо до збірки з потрібними нам параметрами
./configure --prefix=/etc/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log-http-log-path=/var/log/nginx/access.log --pid-path=/var/run/nginx.pid --lock-path=/var/run/nginx.lock-http-client-body-temp-path=/var/cache/nginx/client_temp --http-proxy-temp-path=/var/cache/nginx/proxy_temp --http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp --http uwsgi-temp-path=/var/cache/nginx/uwsgi_temp --http scgi-temp-path=/var/cache/nginx/scgi_temp --user=nginx --group=nginx --with-http_ssl_module --with-http_realip_module --with-http_addition_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_stub_status_module --with-http_auth_request_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_geoip_module=dynamic --with-http_perl_module=dynamic --with-threads --with-stream --with-stream_ssl_module --add-module=spnego-http-auth-nginx-module --with-http_slice_module --with-mail --with-mail_ssl_module --with-file-aio --with-ipv6 --with-http_v2_module --with-debug --with-cc-opt='-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,--as-needed'

Природно утиліти для складання повинні бути встановлені в системі, а nginx повинен бути погашений.
make
make install

Після процедури у нас в результаті тепер робочий самосборный nginx з потрібним нам модулем. Перевірити це можна також nginx -V і подивитися в параметрах наявність модуля.


Для прикладу використаємо url для авторизації test.intranet.com домен intranet.com


Пора трохи попрацювати з самбою, додамо користувача, якого повісимо service principal name (spn) для авторизації через Kerberos
samba-tool add user HTTP
samba-tool user setexpiry HTTP --noexpiry
samba-tool spn add HTTP/test.intranet.com HTTP
samba-tool spn add host/test.intranet.com HTTP

Створимо Kerberos keytab файл для nginx
samba-tool domain exportkeytab /etc/http.keytab --principal=HTTP/test.intranet.com
samba-tool domain exportkeytab /etc/http.keytab --principal=host/test.intranet.com

Перевіримо створений keytab
klist -ke /etc/http.keytab
Keytab name: FILE:/etc/http.keytab
KVNO Principal
---- --------------------------------------------------------------------------
1 host/test.intranet.com@INTRANET.COM (des-cbc-crc) 
1 host/test.intranet.com@INTRANET.COM (des-cbc-md5) 
1 host/test.intranet.com@INTRANET.COM (arcfour-hmac) 
1 HTTP/test.intranet.com@INTRANET.COM (des-cbc-crc) 
1 HTTP/test.intranet.com@INTRANET.COM (des-cbc-md5) 
1 HTTP/test.intranet.com@INTRANET.COM (arcfour-hmac)

Авторізуємось на контролері домену через kerberos
kinit administrator
Password for administrator@INTRANET.COM:
Warning: Your password will expire in 39 days on Птн 30 січ 2016 11:23:11

Перевіряємо авторизацію в домені за spn з допомогою keytab-файлу:
kinit -V -k -t /etc/http.keytab HTTP/test.intranet.com@INTRANET.COM
Using default cache: /tmp/krb5cc_0
Using principal: HTTP/test.intranet.com@INTRANET.COM
Using keytab: /etc/http.keytab
Authenticated to Kerberos v5

У мене на даному етапі була проблема, аутентифікація ніяк не хотіла проходити. Помилка:
kinit: Client not found in Kerberos database while getting initial credentials
Перерив пів інтернету, в результаті знайшлося рішення, виявилося samba-tool відпрацьовує не так, як замислювалося Microsoft, несподівано, правда?
Для вирішення проблеми йдемо на віндовий машину і з допомогою адмистративной консолі Active Directory — користувачі й комп'ютери» правимо нашого користувача HTTP, а саме правимо поле ім'я користувача для входу на — HTTP/test.intranet.com
Після цієї процедури все працює.

Пора перейти до конфігурації nginx, дивимося мій конфіг віртуального хосту
server {
listen *:Ssl 443;
server_name test.intranet.com;

# error_log /var/log/nginx/debug.debug log;

ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;

location / {

http proxy_pass://********/$request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

auth_gss on;
auth_gss_realm INTRANET.COM;
auth_gss_keytab /etc/http.keytab;
auth_gss_service_name HTTP/test.intranet.com;
# auth_gss_allow_basic_fallback off;
}

}


Параметр auth_gss_allow_basic_fallback off; дозволяє вимкнути запит basic авторизації якщо щось пішло не так, припустимо юзер не в домені.


Для роботи прозорою авторизації необхідне виконання деяких умов:
  • Клієнтська машина складається в домені Windows 2003 або вище
  • Користувач залягання в домен
  • Звернення до хосту йде через HTTPS (з моїх тестів працює і з http)
  • Хост внесений у зону Intranet security zone в IE
  • Ім'я хоста є в DNS під A записом
  • Ім'я хоста лежить у зоні домену (приклад — xxxx.intranet.com)
  • Ви коректно створили Service Principal Names (SPNs) в Active Directory, а також замапили на service account (в нашому випадку HTTP)


Залишається на машині внести наш URL — test.intranet.com в зону Intranet security zone в IE і пробувати зайти за нашою посиланням. Якщо все налаштовано правильно, то nginx повинен прозоро пропустити юзера на сайт. На стороні сервера, куди ми власне проксируем з'єднання, в заголовках пакетів можна зловити наступну інформацію.
[PHP_AUTH_USER] => Administrator [PHP_AUTH_PW] => bogus_auth_gss_passwd
Залишається трохи допилити web додаток для прозорої аутентифікації, але то справа вже web програміста…

В інших браузерах цей механізм так само працює з невеликими доопрацюваннями.
  • Firefox входимо в «about:config» шукаємо параметри з «negotiate»
    Додаємо наш сайт в параметр «network.negotiate-auth.trusted-uris» наприклад
    "http://test.intranet.com"
    Параметр «network.negotiate-auth.using-native-gsslib» повинен бути true.
  • Для роботи Chrome, його потрібно запускати з параметром:
    google chrome --auth-server-whitelist="http://test.intranet.com" --auth-negotiate-delegate-whitelist="http://test.intranet.com"
    


Власне ось і весь процес установки, убив я на нього пару днів, вирішив поділитися з громадськістю. Даний механізм дозволяє позбавити користувачів в офісі від введення логіна\пароля при доступі до якогось внутрішнього web додатком.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.