Auth HTTP#

Authenticates mail clients through an external HTTP server, the authentication server, which also chooses the backend for each session. Angie has no other source of backend addresses for mail, so every server in the mail block needs the auth_http directive (see How It Works).

Configuration Example#

Angie proxies IMAP sessions to one of two backends, chosen by the domain in the user name, and acts as its own authentication server through a location in its http block. Place the mail block at the top level of angie.conf, and the map and server blocks inside the existing http block:

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;
        }
    }
}

This authentication server routes clients but does not check their passwords: Angie logs in to the backend with the password the client sent, and the backend accepts or rejects it. If the backend rejects it, proxy_pass_error_message passes the backend's reply to the client, and Angie closes the connection. A user from any other domain gets the Invalid login or password error. On the first nine attempts in a session, Angie delays that error by three seconds and lets the client try again; from the tenth attempt on, it sends the error at once and closes the connection.

Directives#

auth_http#

Syntax

auth_http uri;

Default

—

Context

mail, server

Sets the URL of the authentication server: an IP address or a domain name with an optional port (80 by default) and URI, or a UNIX-domain socket path after the unix: prefix, as in unix:/run/mail-auth.sock:/mail-auth. The http:// scheme prefix is optional. HTTPS is not supported: an https:// URL fails the configuration test with invalid port in auth_http. Angie resolves a domain name when it loads the configuration and sends requests to the first address found.

The directive is mandatory: if neither a server nor the mail block sets it, the configuration test fails with the no "auth_http" is defined for server error. The requests and responses are described in Protocol.

auth_http_header#

Syntax

auth_http_header header value;

Default

—

Context

mail, server

Adds the header to the requests sent to the authentication server. The directive can be specified several times. These directives are inherited from the previous configuration level if and only if there are no auth_http_header directives defined on the current level.

A secret header lets the authentication server check that a request comes from Angie:

auth_http_header X-Auth-Key "secret_string";

auth_http_pass_client_cert#

Syntax

auth_http_pass_client_cert on | off;

Default

auth_http_pass_client_cert off;

Context

mail, server

Adds the Auth-SSL-Cert header with the client certificate in PEM format, URL-encoded, to the requests sent to the authentication server. Angie sends the header only when ssl_verify_client is enabled and the client presents a certificate.

auth_http_timeout#

Syntax

auth_http_timeout time;

Default

auth_http_timeout 60s;

Context

mail, server

Sets the timeout for the exchange with the authentication server: within this time, Angie must connect to it, send the request, and receive the response headers.

Protocol#

On each login attempt, Angie opens a new connection to the authentication server and sends an HTTP/1.0 GET request for the URI set by auth_http; the client's data travel in the request headers. An SMTP client that sends mail without authenticating triggers the request after its RCPT TO command.

The authentication server answers in the response headers. Angie ignores the status code and the response body. The status line, the headers, and the empty line after them must fit in 1024 bytes: with a longer header block, the session fails as described in Errors, and the client may wait until auth_http_timeout expires before getting the error.

Request Headers#

Host

The host from the auth_http URL; localhost for a UNIX-domain socket.

Auth-Method

The authentication method the client used: plain (also for AUTH LOGIN, the IMAP LOGIN command, and POP3 USER and PASS), apop, cram-md5, external, xoauth2, or oauthbearer; none for an SMTP client that sends mail without authenticating.

Auth-User

The user name the client sent; for XOAUTH2 and OAUTHBEARER, the user identity from the initial SASL response.

Auth-Pass

The password the client sent; the client's digest for APOP and CRAM-MD5; the bearer token for XOAUTH2 and OAUTHBEARER; empty for EXTERNAL.

Auth-Salt

APOP and CRAM-MD5 only: the challenge that Angie sent to the client.

Auth-Protocol

imap, pop3, or smtp.

Auth-Login-Attempt

The number of the client's login attempt in the session, starting from 1.

Client-IP

The client's IP address.

Client-Host

SMTP only: the client's host name found by the resolver; [UNAVAILABLE] if the resolver is not configured, the name does not exist, or it does not resolve back to the client's address; [TEMPUNAVAIL] on other resolution errors.

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

With Auth-Method: none only: the argument of the client's HELO or EHLO command, and its full MAIL FROM and RCPT TO commands.

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

With the proxy_protocol parameter of listen only: the client address and port and the server address and port from the PROXY protocol header.

Auth-SSL

on if the client connection uses SSL/TLS, including after STARTTLS.

Auth-SSL-Protocol, Auth-SSL-Cipher

The protocol and the cipher of the client's SSL/TLS connection.

Auth-SSL-Verify

With ssl_verify_client enabled only: the result of client certificate verification: SUCCESS, FAILED:reason, or NONE if the client presented no certificate. FAILED arrives only with ssl_verify_client optional_no_ca and only for a self-signed certificate or one whose issuer is unknown; any other failed verification ends the session before the request.

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

With ssl_verify_client enabled and a client certificate presented only: the certificate's subject and issuer DN in RFC 2253 format, its serial number, and its SHA-1 fingerprint.

Auth-SSL-Cert

Under the same conditions, if auth_http_pass_client_cert is also enabled: the client certificate in PEM format.

Headers set by auth_http_header follow these. In Auth-User, Auth-Pass, and Auth-SSL-Cert, Angie replaces spaces, percent signs, and control characters with %XX escapes, so the authentication server has to decode these values before using them.

Response Headers#

Auth-Status

OK accepts the client. WAIT makes Angie repeat the request after the Auth-Wait delay. Any other value rejects the client and becomes the error message sent to it. Angie matches OK and WAIT case-sensitively; a response without Auth-Status also accepts the client.

Auth-Server

With OK: the IP address of the backend. A domain name is not accepted.

Auth-Port

With OK: the port of the backend.

Auth-User

With OK: the user name for logging in to the backend instead of the one the client sent.

Auth-Pass

With OK: the password for logging in to the backend instead of the one the client sent. Required after APOP, CRAM-MD5, and EXTERNAL: for IMAP and POP3 always, for SMTP if proxy_smtp_auth is enabled.

Auth-Wait

A delay in seconds, used only with an error or WAIT. With an error, Angie waits this long, sends the error, and lets the client try again; without the header, Angie sends the error at once and closes the connection. With WAIT, it is the delay before the repeated request.

Auth-Error-Code

SMTP only, with an error: the reply code and the enhanced status code that precede the message; 535 5.7.0 by default.

Auth-Error-SASL

XOAUTH2 and OAUTHBEARER only, with an error: a SASL challenge that Angie sends to the client before the error.

Angie ignores other response headers. However, a header name may contain only Latin letters, digits, and hyphens: a name with any other character, such as an underscore, makes Angie reject the whole response.

Examples of Requests and Responses#

Successful Login#

An IMAP client logs in with a user name and a password:

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

The authentication server accepts the client and names the backend:

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

Angie connects to 198.51.100.1:143 and logs in with the client's user name and password.

Failed Login and Retries#

The authentication server rejects the client:

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

After three seconds, Angie sends the client the error in the form its protocol expects (-ERR Invalid login or password in POP3, a tagged NO reply in IMAP, 535 5.7.0 Invalid login or password in SMTP) and lets it try again; the next request carries the incremented Auth-Login-Attempt.

Angie allocates memory for each attempt and frees it only when the session ends, so the authentication server should limit the attempts: after 10-20 of them, it should respond without Auth-Wait, so that Angie closes the connection.

For SMTP, Auth-Error-Code replaces the default reply code. This response:

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

gives the SMTP client this error:

451 4.3.0 Temporary server problem, try again later

If the authentication server cannot decide yet, it can respond with Auth-Status: WAIT. Angie then sends the request again after the Auth-Wait delay, without telling the client, and Auth-Login-Attempt stays the same. For APOP and CRAM-MD5, the repeated request carries an empty Auth-Pass, so the authentication server has to check the digest on the first request and remember the result. Angie keeps repeating the request as long as the answer is WAIT, even after the client disconnects, so the authentication server should stop answering WAIT after a reasonable time.

Warning

Every WAIT response must carry Auth-Wait. Without it, Angie repeats the request at once, in a tight loop, and keeps doing so even when the authentication server later answers OK.

APOP, CRAM-MD5, and EXTERNAL#

With APOP or CRAM-MD5, the client proves that it knows the password without sending it, and the request carries the challenge and the client's digest:

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 logs in to the backend with plain-text commands only, so the authentication server checks the digest itself and returns the user's password:

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

EXTERNAL needs Auth-Pass in the response the same way; its request carries an empty Auth-Pass.

XOAUTH2 and OAUTHBEARER#

On success, Angie logs in to the backend with the bearer token as the password, unless the response carries Auth-Pass.

An error response may also include Auth-Error-SASL. Angie sends its value to the client as an additional SASL challenge (SMTP: 334, IMAP and POP3: +). After the client responds (with an empty line for XOAUTH2 or AQ== for OAUTHBEARER), Angie returns the error from Auth-Status.

SMTP Without Authentication#

If smtp_auth includes none and the client sends mail without authenticating, the request carries the client's SMTP commands:

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>

The authentication server still has to name the backend in Auth-Server and Auth-Port; Angie then repeats the client's MAIL FROM and RCPT TO commands to it.

SSL/TLS Client Connections#

An IMAP client connected over TLS, with ssl_verify_client enabled:

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

Errors#

If the exchange with the authentication server fails, or its response accepts the client but cannot be used, Angie sends the client an internal error and closes the connection:

IMAP

* BAD internal server error

POP3

-ERR internal server error

SMTP

451 4.3.2 Internal server error

The error_log names the cause:

timed out

The exchange did not complete within auth_http_timeout.

sent invalid response

The status line ends with a CR that is not followed by LF.

sent invalid header in response

A response header is malformed, or its name contains a character other than a Latin letter, digit, or hyphen.

did not send server or port

The response does not reject the client but lacks Auth-Server or Auth-Port, as an error page returned for a wrong URI does.

sent invalid server address

Auth-Server is not an IP address.

sent invalid server port

Auth-Port is not a number from 1 to 65535.

did not send password

An IMAP or POP3 response accepts an APOP, CRAM-MD5, or EXTERNAL client without Auth-Pass.

no password available

An SMTP response accepts a CRAM-MD5 or EXTERNAL client without Auth-Pass while proxy_smtp_auth is enabled.

All these messages except no password available start with auth http server and the server's address. If Angie cannot connect to the authentication server, the log shows the system error in a connect() to ... failed, send() failed, or recv() failed message. A response whose header block exceeds 1024 bytes is logged as timed out, if at all.