Auth HTTP#

Выполняет аутентификацию почтовых клиентов с помощью внешнего HTTP-сервера — сервера аутентификации, который также выбирает бэкенд для каждой сессии. Других источников адреса бэкенда у почтового прокси Angie нет, поэтому директива auth_http нужна каждому server в блоке mail (см. Принцип работы).

Пример конфигурации#

Angie проксирует IMAP-сессии на один из двух бэкендов в зависимости от домена в имени пользователя и сам выступает сервером аутентификации — через location в своем блоке http. Блок mail поместите на верхний уровень angie.conf, а блоки map и server — внутрь существующего блока http:

mail {
    auth_http                127.0.0.1:9000/mail-auth;
    proxy_pass_error_message on;

    server {
        listen   143;
        protocol imap;
    }
}

http {
    map $http_auth_user $mail_backend {
        ~@example\.com$ 192.0.2.10;
        ~@example\.org$ 192.0.2.20;
    }

    map $mail_backend $mail_auth_status {
        ""      "Invalid login or password";
        default OK;
    }

    map $http_auth_login_attempt $mail_auth_wait {
        ~^[1-9]$ 3;
        default  "";
    }

    server {
        listen 127.0.0.1:9000;

        location = /mail-auth {
            add_header Auth-Status $mail_auth_status;
            add_header Auth-Server $mail_backend;
            add_header Auth-Port   143;
            add_header Auth-Wait   $mail_auth_wait;

            return 204;
        }
    }
}

Такой сервер аутентификации только распределяет клиентов и не проверяет пароли: Angie входит на бэкенд с паролем, который прислал клиент, и уже бэкенд принимает или отклоняет вход. Если бэкенд отклоняет вход, благодаря директиве proxy_pass_error_message клиент получает ответ бэкенда, после чего Angie закрывает соединение. Пользователь из любого другого домена получает ошибку Invalid login or password. На первых девяти попытках в сессии Angie выдает эту ошибку с задержкой в три секунды и позволяет клиенту повторить вход; начиная с десятой — выдает ее сразу и закрывает соединение.

Директивы#

auth_http#

Синтаксис

auth_http uri;

По умолчанию

—

Контекст

mail, server

Задает URL сервера аутентификации: IP-адрес или доменное имя с необязательным портом (по умолчанию 80) и URI либо путь к UNIX-сокету после префикса unix:, например unix:/run/mail-auth.sock:/mail-auth. Префикс схемы http:// необязателен. HTTPS не поддерживается: с URL вида https:// проверка конфигурации завершается ошибкой invalid port in auth_http. Angie преобразует доменное имя в адрес при загрузке конфигурации и отправляет запросы на первый найденный адрес.

Директива обязательна: если ее не задает ни server, ни блок mail, проверка конфигурации завершается ошибкой no "auth_http" is defined for server. Запросы и ответы описаны в разделе Протокол.

auth_http_header#

Синтаксис

auth_http_header заголовок значение;

По умолчанию

—

Контекст

mail, server

Добавляет заголовок к запросам, отправляемым на сервер аутентификации. Директиву можно указать несколько раз. Директивы наследуются с предыдущего уровня конфигурации тогда и только тогда, когда на текущем уровне не задано ни одной директивы auth_http_header.

Секретный заголовок позволяет серверу аутентификации убедиться, что запрос пришел от Angie:

auth_http_header X-Auth-Key "secret_string";

auth_http_pass_client_cert#

Синтаксис

auth_http_pass_client_cert on | off;

По умолчанию

auth_http_pass_client_cert off;

Контекст

mail, server

Добавляет к запросам на сервер аутентификации заголовок Auth-SSL-Cert с клиентским сертификатом в формате PEM в URL-кодировке. Angie передает заголовок, только если включена директива ssl_verify_client и клиент предъявил сертификат.

auth_http_timeout#

Синтаксис

auth_http_timeout время;

По умолчанию

auth_http_timeout 60s;

Контекст

mail, server

Задает таймаут обмена с сервером аутентификации: за это время Angie должен подключиться к нему, отправить запрос и получить заголовки ответа.

Протокол#

При каждой попытке входа Angie открывает новое соединение с сервером аутентификации и отправляет HTTP/1.0-запрос GET на URI, заданный директивой auth_http; данные клиента передаются в заголовках запроса. Если SMTP-клиент отправляет почту без аутентификации, запрос уходит после его команды RCPT TO.

Сервер аутентификации отвечает в заголовках ответа. Angie игнорирует код статуса и тело ответа. Строка статуса, заголовки и пустая строка после них должны умещаться в 1024 байта: если блок заголовков длиннее, сессия завершается ошибкой, как описано в разделе Ошибки, причем клиент может получить ее только по истечении auth_http_timeout.

Заголовки запроса#

Host

Хост из URL в директиве auth_http; localhost для UNIX-сокета.

Auth-Method

Метод аутентификации, который использовал клиент: plain (в том числе для AUTH LOGIN, IMAP-команды LOGIN и POP3-команд USER и PASS), apop, cram-md5, external, xoauth2 или oauthbearer; none — для SMTP-клиента, который отправляет почту без аутентификации.

Auth-User

Имя пользователя, которое прислал клиент; для XOAUTH2 и OAUTHBEARER — идентификатор пользователя из начального SASL-ответа.

Auth-Pass

Пароль, который прислал клиент; для APOP и CRAM-MD5 — дайджест клиента; для XOAUTH2 и OAUTHBEARER — токен bearer; для EXTERNAL — пустое значение.

Auth-Salt

Только для APOP и CRAM-MD5: строка вызова, которую Angie отправил клиенту.

Auth-Protocol

imap, pop3 или smtp.

Auth-Login-Attempt

Номер попытки входа клиента в сессии, начиная с 1.

Client-IP

IP-адрес клиента.

Client-Host

Только для SMTP: имя хоста клиента, найденное с помощью resolver; [UNAVAILABLE], если резолвер не настроен, имя не существует или не указывает обратно на адрес клиента; [TEMPUNAVAIL] при других ошибках преобразования.

Auth-SMTP-Helo, Auth-SMTP-From, Auth-SMTP-To

Только при Auth-Method: none: аргумент команды HELO или EHLO клиента и его команды MAIL FROM и RCPT TO целиком.

Proxy-Protocol-Addr, Proxy-Protocol-Port, Proxy-Protocol-Server-Addr, Proxy-Protocol-Server-Port

Только с параметром proxy_protocol директивы listen: адрес и порт клиента и адрес и порт сервера из заголовка протокола PROXY.

Auth-SSL

on, если клиентское соединение использует SSL/TLS, в том числе после STARTTLS.

Auth-SSL-Protocol, Auth-SSL-Cipher

Протокол и шифр SSL/TLS-соединения клиента.

Auth-SSL-Verify

Только при включенной директиве ssl_verify_client: результат проверки клиентского сертификата — SUCCESS, FAILED:причина или NONE, если клиент не предъявил сертификат. FAILED приходит только при ssl_verify_client optional_no_ca и только для самоподписанного сертификата или сертификата с неизвестным издателем; при любой другой неудачной проверке сессия завершается до запроса.

Auth-SSL-Subject, Auth-SSL-Issuer, Auth-SSL-Serial, Auth-SSL-Fingerprint

Только при включенной директиве ssl_verify_client, если клиент предъявил сертификат: DN субъекта и издателя сертификата в формате RFC 2253, его серийный номер и отпечаток SHA-1.

Auth-SSL-Cert

При тех же условиях, если также включена директива auth_http_pass_client_cert: клиентский сертификат в формате PEM.

За ними следуют заголовки, заданные директивой auth_http_header. В Auth-User, Auth-Pass и Auth-SSL-Cert Angie заменяет пробелы, знаки процента и управляющие символы escape-последовательностями %XX, поэтому сервер аутентификации должен декодировать эти значения перед использованием.

Заголовки ответа#

Auth-Status

OK принимает клиента. WAIT заставляет Angie повторить запрос после задержки из Auth-Wait. Любое другое значение отклоняет клиента и становится текстом ошибки, которую он получит. OK и WAIT Angie сравнивает с учетом регистра; ответ без Auth-Status тоже принимает клиента.

Auth-Server

При OK: IP-адрес бэкенда. Доменное имя не допускается.

Auth-Port

При OK: порт бэкенда.

Auth-User

При OK: имя пользователя для входа на бэкенд вместо того, которое прислал клиент.

Auth-Pass

При OK: пароль для входа на бэкенд вместо того, который прислал клиент. Обязателен после APOP, CRAM-MD5 и EXTERNAL: для IMAP и POP3 — всегда, для SMTP — если включена директива proxy_smtp_auth.

Auth-Wait

Задержка в секундах; учитывается только при ошибке или WAIT. При ошибке Angie выжидает это время, отправляет ошибку и позволяет клиенту повторить вход; без этого заголовка Angie отправляет ошибку сразу и закрывает соединение. При WAIT — задержка перед повторным запросом.

Auth-Error-Code

Только для SMTP, при ошибке: код ответа и расширенный код статуса перед текстом ошибки; по умолчанию 535 5.7.0.

Auth-Error-SASL

Только для XOAUTH2 и OAUTHBEARER, при ошибке: SASL-вызов, который Angie отправляет клиенту перед ошибкой.

Angie игнорирует остальные заголовки ответа. Однако имя заголовка может содержать только латинские буквы, цифры и дефисы: если в имени есть любой другой символ, например подчеркивание, Angie отвергает весь ответ.

Примеры запросов и ответов#

Успешный вход#

IMAP-клиент входит с именем пользователя и паролем:

GET /auth HTTP/1.0
Host: localhost
Auth-Method: plain
Auth-User: user
Auth-Pass: password
Auth-Protocol: imap
Auth-Login-Attempt: 1
Client-IP: 192.0.2.42

Сервер аутентификации принимает клиента и указывает бэкенд:

HTTP/1.0 200 OK
Auth-Status: OK
Auth-Server: 198.51.100.1
Auth-Port: 143

Angie подключается к 198.51.100.1:143 и входит на него с именем пользователя и паролем клиента.

Неудачный вход и повторные попытки#

Сервер аутентификации отклоняет клиента:

HTTP/1.0 200 OK
Auth-Status: Invalid login or password
Auth-Wait: 3

Через три секунды Angie отправляет клиенту ошибку в принятом в его протоколе виде (-ERR Invalid login or password в POP3, ответ NO с тегом команды в IMAP, 535 5.7.0 Invalid login or password в SMTP) и позволяет повторить вход; следующий запрос придет с увеличенным Auth-Login-Attempt.

Angie выделяет память под каждую попытку и освобождает ее только по окончании сессии, поэтому число попыток должен ограничивать сервер аутентификации: после 10-20 попыток ему следует отвечать без Auth-Wait, чтобы Angie закрыл соединение.

Для SMTP заголовок Auth-Error-Code заменяет код ответа по умолчанию. Например, получив от сервера аутентификации такой ответ:

HTTP/1.0 200 OK
Auth-Status: Temporary server problem, try again later
Auth-Error-Code: 451 4.3.0
Auth-Wait: 3

Angie выдаст SMTP-клиенту ошибку:

451 4.3.0 Temporary server problem, try again later

Если сервер аутентификации пока не может принять решение, он может ответить Auth-Status: WAIT. Тогда Angie повторит запрос после задержки из Auth-Wait, ничего не сообщая клиенту, а Auth-Login-Attempt не изменится. Для APOP и CRAM-MD5 повторный запрос придет с пустым Auth-Pass, поэтому сервер аутентификации должен проверить дайджест при первом запросе и запомнить результат. Angie повторяет запрос, пока ответ равен WAIT, даже после того как клиент отключился, поэтому серверу аутентификации следует через разумное время перестать отвечать WAIT.

Предупреждение

Каждый ответ WAIT должен содержать Auth-Wait. Без него Angie повторяет запрос сразу и без пауз и продолжает повторять его, даже когда сервер аутентификации затем отвечает OK.

APOP, CRAM-MD5 и EXTERNAL#

При APOP и CRAM-MD5 клиент доказывает знание пароля, не передавая его, и запрос содержит строку вызова и дайджест клиента:

GET /auth HTTP/1.0
Host: localhost
Auth-Method: apop
Auth-User: user
Auth-Salt: <238188073.1163692009@mail.example.com>
Auth-Pass: auth_response
Auth-Protocol: pop3
Auth-Login-Attempt: 1
Client-IP: 192.0.2.42

Angie входит на бэкенд только командами с паролем в открытом виде, поэтому сервер аутентификации сам проверяет дайджест и возвращает пароль пользователя:

HTTP/1.0 200 OK
Auth-Status: OK
Auth-Server: 198.51.100.1
Auth-Port: 110
Auth-Pass: plain-text-pass

Для EXTERNAL ответ так же должен содержать Auth-Pass: в запросе этот заголовок пустой.

XOAUTH2 и OAUTHBEARER#

При успехе Angie входит на бэкенд с токеном bearer в качестве пароля, если ответ не содержит Auth-Pass.

Ответ с ошибкой может также содержать заголовок Auth-Error-SASL. Его значение Angie отправляет клиенту как дополнительный SASL-вызов (SMTP: 334, IMAP и POP3: +). После ответа клиента (пустая строка для XOAUTH2 или AQ== для OAUTHBEARER) Angie возвращает ошибку из Auth-Status.

SMTP без аутентификации#

Если smtp_auth включает none и клиент отправляет почту без аутентификации, запрос передает SMTP-команды клиента:

GET /auth HTTP/1.0
Host: localhost
Auth-Method: none
Auth-User:
Auth-Pass:
Auth-Protocol: smtp
Auth-Login-Attempt: 1
Client-IP: 192.0.2.42
Client-Host: client.example.org
Auth-SMTP-Helo: client.example.org
Auth-SMTP-From: MAIL FROM: <>
Auth-SMTP-To: RCPT TO: <postmaster@mail.example.com>

Сервер аутентификации и в этом случае должен указать бэкенд в Auth-Server и Auth-Port; затем Angie повторяет на нем команды клиента MAIL FROM и RCPT TO.

Клиентские SSL/TLS-соединения#

IMAP-клиент подключен по TLS, директива ssl_verify_client включена:

GET /auth HTTP/1.0
Host: localhost
Auth-Method: plain
Auth-User: user
Auth-Pass: password
Auth-Protocol: imap
Auth-Login-Attempt: 1
Client-IP: 192.0.2.42
Auth-SSL: on
Auth-SSL-Protocol: TLSv1.3
Auth-SSL-Cipher: TLS_AES_256_GCM_SHA384
Auth-SSL-Verify: SUCCESS
Auth-SSL-Subject: CN=example.com
Auth-SSL-Issuer: CN=example.com
Auth-SSL-Serial: C07AD56B846B5BFF
Auth-SSL-Fingerprint: 29d6a80a123d13355ed16b4b04605e29cb55a5ad

Ошибки#

Если обмен с сервером аутентификации не удался или его ответ принимает клиента, но не может быть использован, Angie отправляет клиенту сообщение о внутренней ошибке и закрывает соединение:

IMAP

* BAD internal server error

POP3

-ERR internal server error

SMTP

451 4.3.2 Internal server error

Причину называет запись в error_log:

timed out

Обмен не завершился за время auth_http_timeout.

sent invalid response

Строка статуса заканчивается символом CR, за которым не следует LF.

sent invalid header in response

Заголовок ответа имеет неверный формат или его имя содержит символ, отличный от латинской буквы, цифры или дефиса.

did not send server or port

Ответ не отклоняет клиента, но не содержит Auth-Server или Auth-Port — так выглядит, например, страница ошибки, полученная из-за неверного URI.

sent invalid server address

Auth-Server не является IP-адресом.

sent invalid server port

Auth-Port не является числом от 1 до 65535.

did not send password

Ответ для IMAP или POP3 принимает клиента с APOP, CRAM-MD5 или EXTERNAL без Auth-Pass.

no password available

Ответ для SMTP принимает клиента с CRAM-MD5 или EXTERNAL без Auth-Pass, а директива proxy_smtp_auth включена.

Все эти сообщения, кроме no password available, начинаются с auth http server и адреса сервера. Если Angie не удается подключиться к серверу аутентификации, системная ошибка попадает в журнал в сообщении connect() to ... failed, send() failed или recv() failed. Ответ с блоком заголовков длиннее 1024 байт попадает в журнал как timed out или не попадает в него вовсе.