Задача:
Есть frontend (nginx) - скажем для https://internal.com.
frontend проксирует запросы к backend'ам.
Аутентификация - HTTP Basic (поскольку используется строго SSL, то
паранойя приглушённо молчит).
Но, сама аутентификация и авторизация происходит на backend'ах -
пользователи хранятся в LDAP-сервере, доступ к ресурсам регулируется на
основе их вхождения в LDAP-группы и другими странными способами (скажем
через authz_svn).
Кроме всего этого nginx отдает статику - которая тоже предмет контроля
доступа.
Что хочется - аутентифицировать по HTTP Basic через внешний "authenticator".
Т.е. вместо директивы "auth_basic_user_file" использовать нечто иное -
желательно как можно более гибкое.
Видятся варианты:
1. Заголовок "Authorization"
Идея проста - проверять в if () наличия заголовка "Authorization", если
его нет - форсировать процесс запроса credentials у пользователя.
Если же есть - передавать запрос далее backend'у, который уже сам всё
проверит.
server {
...
if ($http_authorization !~ Basic) {
add_header WWW-Authenticate "Basic realm=\"closed site\"";
return 401;
}
Вариант теоретически рабочий (только для обработки статики придется
делать где-то на backend'е специальный handler, который будет каждый раз
проверять credentials и при успешной авторизации возвращать
Accel-Redirect на реальный файл).
"теоретически" рабочий - потому что add_header сейчас срабатывает только
для 200|204|301|302|304.
Возможно, имеет смысл добавить директиву типа "error_add_header" - по
аналогии с "err_headers_out" в Apache/mod_perl.
2. FCGI_AUTHORIZER.
Мощный способ, поскольку кроме аутентификации может и производить
авторизацию. (Кстати, есть в lighttpd.)
location /restricted {
auth_basic "closed site";
auth_basic_authnz_location /check_user;
}
location /check_user {
internal;
fastcgi_pass localhost:9000;
fastcgi_role authorizer;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REMOTE_USER $remote_user;
fastcgi_param REMOTE_PASSWD $remote_passwd;
fastcgi_param AUTH_REALM $auth_realm;
}
Далее вроде все понятно. С реализованным мультиплексированием запросов
был бы вообще отличный вариант.
3. "auth_http" - как для IMAP
location /restricted {
auth_basic "closed site";
auth_http 127.0.0.1:80/auth;
}
Далее как обычно.
Что передавать: "Auth-User", "Auth-Pass"
Что возвращает handler: "Auth-Status" = (200|401|403)
4. perl handler
Аналигично чему-то вышеописанному - на вход дается тройка (username,
password, query_string) - на выходе решение 200|401|403.
----------------
Итог - в общем-то нужно решить задачку, а не создавать сверхгибкое решение.
Но, всё же хочется видеть right-way направление - ведь интуитивно есть
такая штука как "nginx style" :)
--
Sergey Skvortsov
mailto: skv@xxxxxxxxx