Назад | Перейти на главную страницу

Авторизация на основе настраиваемого заголовка (Apache)

У меня есть служба, работающая за обратным прокси-сервером 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)