У меня есть служба, работающая за обратным прокси-сервером Apache, которая использует настраиваемые заголовки «имя пользователя» и «роль» для идентификации пользователей и их роли.
Я хочу, чтобы Apache HTTPD ограничивал доступ для людей, чей пользовательский HTTP-заголовок «groupmembership» содержит одно из следующих значений: «зритель», «издатель», «администратор».
Apache находится за другим прокси-сервером, который аутентифицирует пользователей и заполняет HTTP-заголовки «имя пользователя» и «членство в группе», где содержимое «членство в группах» представляет собой список групп, разделенных запятыми.
Для справки я включил проект архитектуры. http-прокси-auth
Как это возможно? Я пробовал использовать директиву require, например Require expr %{HTTP:iv_groupmembership} in { 'viewer', 'publisher', 'administrator' }
внутри <Location />
но безрезультатно.
Может ли это работать с mod_rewrite?
Вот конфигурация обратного прокси с использованием mod_proxy и mod_rewrite:
RewriteEngine on
<Proxy *>
Allow from all
</Proxy>
ProxyRequests Off
# store variable values with dummy rewrite rules
RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
RewriteRule . - [E=http_host:%{HTTP_HOST}]
RewriteRule . - [E=req_uri:%{REQUEST_URI}]
# set header with variables
RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_host}e%{req_uri}e"
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:3939/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:3939/$1 [P,L]
ProxyPass / http://172.17.0.1:3939/
ProxyPassReverse / http://172.17.0.1:3939/
Спасибо за любые подсказки.
Изменить: в основном вопрос сводится к следующему: как я могу проверить, есть ли список, разделенный запятыми, в groupmembership
Заголовок содержит либо "Администратор", "Издатель", либо "Читатель".
Спасибо @Freddy, у меня получилось работать с Require
и Expressions для части авторизации и размещения RequestHeader
директива внутри <Virtualhost>
для установки заголовков ролей.
Окончательный конфиг выглядит так:
<VirtualHost *:443>
ServerName ...
DocumentRoot /var/www/html
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite HIGH:3DES:!aNULL:!MD5:!SEED:!IDEA
SSLCertificateFile /etc/httpd/ssl/...
SSLCertificateKeyFile /etc/httpd/ssl/...
RewriteEngine on
#ProxyPreserveHost on
<Proxy *>
Allow from all
</Proxy>
ProxyRequests Off
# store variable values with dummy rewrite rules
RewriteRule . - [E=req_scheme:%{REQUEST_SCHEME}]
RewriteRule . - [E=http_host:%{HTTP_HOST}]
RewriteRule . - [E=req_uri:%{REQUEST_URI}]
# set header with variables
RequestHeader set X-RSC-Request "%{req_scheme}e://%{http_host}e%{req_uri}e"
RewriteCond %{HTTP:Upgrade} =websocket
RewriteRule /(.*) ws://localhost:3939/$1 [P,L]
RewriteCond %{HTTP:Upgrade} !=websocket
RewriteRule /(.*) http://localhost:3939/$1 [P,L]
# test for string in comma-separated values, one of the values must match
<If "%{HTTP:iv_groupmembership} !~ /(^|,)(Viewer|Publisher|Administrator)(,|$)/ && -z %{HTTP:X-Auth-Token} && %{HTTP:Authorization} !~ /Key .+/">
Require all denied
</If>
# set role of groupmembership
<If "%{HTTP:iv_groupmembership} =~ /(^|,)Viewer(,|$)/">
RequestHeader set Role viewer
</If>
<ElseIf "%{HTTP:iv_groupmembership} =~ /(^|,)Publisher(,|$)/">
RequestHeader set Role publisher
</ElseIf>
<ElseIf "%{HTTP:iv_groupmembership} =~ /(^|,)Administrator(,|$)/">
RequestHeader set Role administrator
</ElseIf>
</Virtualhost>
Большое спасибо!
Редактировать: как добавить дополнительную логику в Require
директива, так что если заголовок X-Auth-Token
присутствует, доступ все равно предоставляется?
Edit2: Еще раз спасибо @Freddy за указатель на логику выражения Apache, я адаптировал тест на наличие заголовка "X-Auth-Token" с -z %{HTTP:X-Auth-Token}
и может добавить еще одно условие для прохождения запросов, содержащих ключ внутри заголовка «авторизация».
Это должно сработать. Если в заголовке есть список, разделенный запятыми groupmembership
, затем используйте первое выражение регулярного выражения. Одно значение в списке должно соответствовать, чтобы предоставить доступ.
Если вы хотите найти точное значение в iv_groupmembership
, затем раскомментируйте второй третье выражение (и прокомментируйте первое).
Редактировать:
RequestHeader set role
например, при необходимости раскомментируйте. Я тестировал это только с Header set role
(в ответе нет бэкенда), но должен работать с RequestHeader
так же.Edit2:
<Location/>
для ясностиX-Auth-Token
чек в сочетании с groupmembership
Пример конфигурации:
# test for string in comma-separated values, one of the values must match
<If "%{HTTP:groupmembership} !~ /(^|,)(viewer|publisher|administrator)(,|$)/">
# combined: X-Auth-Token must be set or one of the roles must exist
# <If "%{HTTP:X-Auth-Token} == '' && %{HTTP:groupmembership} !~ /(^|,)(viewer|publisher|administrator)(,|$)/">
# alternative: test for a single value in "iv_groupmembership" (exact match)
# <If "! %{HTTP:iv_groupmembership} in { 'viewer', 'publisher', 'administrator' }">
Require all denied
</If>
# set role of groupmembership
# <If "%{HTTP:groupmembership} =~ /(^|,)viewer(,|$)/">
# RequestHeader set role viewer
# </If>
# <ElseIf "%{HTTP:groupmembership} =~ /(^|,)publisher(,|$)/">
# RequestHeader set role publisher
# </ElseIf>
# <ElseIf "%{HTTP:groupmembership} =~ /(^|,)administrator(,|$)/">
# RequestHeader set role administrator
# </ElseIf>
# set role of iv_groupmembership
# RequestHeader set role "expr=%{HTTP:iv_groupmembership}"
Изменение заголовков в Apache (например, RequestHeader set iv_groupmembership "viewer"
) для отладки / тестирования конфигурация не работает, вам нужно установить заголовок очень рано.
https://httpd.apache.org/docs/2.4/expr.html#vars
Синтаксический анализатор выражений предоставляет ряд переменных в форме% {HTTP_HOST}. Обратите внимание, что значение переменной может зависеть от фазы обработки запроса, на которой она оценивается. Например, выражение, используемое в директиве <If>, оценивается до выполнения аутентификации. Следовательно,% {REMOTE_USER} в этом случае не будет установлен.
Вы можете проверить конфигурацию с помощью wget из командной строки, заменив localhost
с вашим именем хоста.
# HTTP/1.1 403 Forbidden
wget -S -O - http://localhost
wget -S -O - --header='groupmembership: xviewer' http://localhost
wget -S -O - --header='groupmembership: administratorx' http://localhost
wget -S -O - --header='iv_groupmembership: xviewer' http://localhost
# HTTP/1.1 200 OK
wget -S -O - --header='groupmembership: foo,viewer' http://localhost
wget -S -O - --header='groupmembership: publisher,foo' http://localhost
wget -S -O - --header='iv_groupmembership: viewer' http://localhost
wget -S -O - --header='iv_groupmembership: publisher' http://localhost
wget -S -O - --header='iv_groupmembership: administrator' http://localhost
Протестировано с Apache / 2.4.25 (Debian)