Repository navigation
mail-auth-proxy 0.2.1
·
38 commits
to main
since this release
Immutable
release. Only release title and notes can be modified.
Added
limits.ipv6_source_prefix(default 64, 32-64): the prefix length by which IPv6
sources are grouped formax_preauth_per_ipand the auth rate limit; 48 treats a
whole site as one source.- Metric
mail_auth_proxy_jwks_keys_skipped_totalbyissuer: JWKS keys skipped because
a member was missing or undecodable, counted on every fetch. Such a key was visible
only as a journal warning.
Changed
- A
server.hostnamethat is a single label, the defaultmail-auth-proxyincluded,
gives a configuration warning: the backend EHLO takes a fully-qualified host name
(RFC 5321 §4.1.4). oauth.issuers[].client_claimdefaults toclient_idfortoken_type = "rfc9068"
(RFC 9068 §2.2);keycloakandanykeepazp. An RFC 9068 issuer with
allowed_clientsthat relied onazpmust now setclient_claim = "azp".- Relative file paths in the configuration (
tls.cert,tls.key,ca_file,
domains_file,doveadm_key_file,doveadm_ca_file,users_file) are a validation
error: they resolved against the working directory, so--check-configin a shell
could pass on files the service never reads. Use absolute paths. - The HELP text of
mail_auth_proxy_ratelimit_active_blocksnames the update interval:
every 10 s and when a block starts.
Fixed
- A token whose JWS header has a
critparameter is refused: the proxy understands no
JWS extension (RFC 7515 §4.1.11). - A token whose
issclaim is an array is refused;issis a string (RFC 7519 §4.1.1). - A JWK with missing or undecodable members is skipped with a warning instead of
discarding the issuer's whole JWKS (RFC 7517 §5). - The JWKS of all issuers are fetched concurrently at startup, on refresh and on an
unknownkid: with several unreachable IdPs a refresh, and every token waiting on
it, took one 10-second timeout per issuer. - The password and rate-limit fingerprint keys are generated at startup: without a
system RNG the proxy now refuses to start instead of panicking in every session that
logs a refused login. - A JWKS response is used only with a 2xx status; a redirect carrying a JWKS body was
accepted. mail_auth_proxy_tls_cert_expiry_timestamp_secondsis 0 for a certificate whose
notAfterhas an impossible hour, minute, second or day (such as 31 April) instead of
a date rolled over into the next day or month.- A full legacy throttle table drops the oldest 1024 accounts at once instead of one per
new failing account, so the table scan under the lock is no longer paid on every new
account; a failure of an account already tracked evicts nothing. - ManageSieve: a backend
BYEin answer toAUTHENTICATE(shutdown, connection limit)
is an outage, not abackend_reject; it no longer counts in the rate limit or for
CrowdSec (RFC 5804 §1.3). - A backend that offers
UNAUTHENTICATE(RFC 8437, RFC 5804 §2.14.1) gets no login: an
outage with a journal line that names it, since a client could otherwise leave its
login and try passwords past the password gate. ManageSieve no longer relays the
capability. - Token validation (including a JWKS refresh for an unknown
kid), the legacy account
check and the backend login now run inside the pre-auth budget (preauth_secs); a
slow IdP or a hanging backend no longer holds pre-auth slots beyond it. Running out is
an outage (retry later), not a failed login. - A password mechanism the endpoint does not offer, chosen without an initial response,
is refused at once (IMAPNO, SMTP504 5.5.4, ManageSieveNO) instead of prompting
for a password that would never be used. It is logged asblocked_endpointwithout
pwfp(and with the login only if the client sent it as SASL LOGIN initial response). - ManageSieve
AUTHENTICATEwithout initial response reads the client's answer as a
string (quoted, literal or bare) and takes"*"as a cancel (RFC 5804 §2.1); a
quoted response was passed to the base64 decoder with its quotes, so such logins
failed. Client literals must be{n+}with nothing after the header or after the
octets (RFC 5804 §4);{n},{n++}and trailing text are refused. - ManageSieve: the greeting lists the backend's
SIEVEcapability from the first
connection after startup on (RFC 5804 §1.7); while the capability cache is cold the
greeting waits for the probe. Probes run one at a time (clients that arrive together
share one), a failed probe counts inmail_auth_proxy_backend_errors_total{proto="sieve"}
and the next one waits 5 s. - SASL parsing is strict where the RFCs are: a NUL in a PLAIN password (RFC 4616 §2), in
a SASL LOGIN field or in the IMAPLOGINarguments is refused; the OAUTHBEARER GS2
header must ben,ory,with an optionala=authzid whose=2C/=3Dare decoded
(RFC 7628 §3.1, RFC 5801 §4),p=channel binding is refused; a XOAUTH2user=or
OAUTHBEARER authzid longer than 255 bytes or with control characters is refused. All
of these end asprotocol, before the gate and the backend. - SMTP: after a refused
AUTH(the proxy takes one per connection) the close is
announced with421 4.7.0 <hostname> closing connectionafter the refusal (RFC 5321
§3.8). - ManageSieve:
CAPABILITYandNOOPwork before STARTTLS too (RFC 5804 §2), and
NOOPwith an argument answers with theTAGresponse code (§2.13). - ManageSieve backend login: a SASL response longer than 1024 octets (any sizable
token) is sent as a literal{n+}instead of an over-long quoted string (RFC 5804
§4). - IMAP backend login: the SASL initial response is only sent when the backend's
greeting advertisesSASL-IR; otherwise the response follows the backend's empty
challenge (RFC 4959 §3). - IMAP: the pre-auth capabilities list
ID, which the proxy answers (RFC 2971 §3). - IMAP and SMTP: an initial response
=is the empty response (RFC 4959 §3, RFC 4954
§4), not undecodable base64. A SASL response that decodes but holds no valid
credential now getsNO [AUTHENTICATIONFAILED]/535 5.7.8instead ofBAD/
501, which stay for responses that are not base64 and for a cancel (RFC 9051
§6.2.2, RFC 4954 §4). - An OAuth response with an empty
authvalue (auth=, orBearerwithout a token) is
a discovery request (RFC 7628 §4.3): it gets the error result withscopeand
openid-configurationlike a rejected token instead of a syntax error. It carries no
credential, so itsauthresultline isreason="protocol"(with the mechanism and
the SASL user), and it counts neither as a failed attempt nor in the rate limit. - OAUTHBEARER: a
hostin the client response must match the TLS server name (SNI),
ASCII case-insensitive (RFC 7628 §3.2); a mismatch is refused like any rejected token
(bad_token). Without SNI, and forport, nothing is compared. systemctl reloadfailed on minimal systems without procps (/bin/kill); the packages
now depend on it (procps for the deb, util-linux-core for the rpm).- An upgrade with a locally changed
/etc/mail-auth-proxy/config.tomlstopped at dpkg's
conffile question whenever the shipped example had changed, and unattended-upgrades
skipped it. The config is no longer a conffile: the package ships the example as
/usr/share/mail-auth-proxy/config.example.toml, createsconfig.tomlfrom it on
install where none exists and never changes an existing one. Upgrading from a release
that shipped it as conffile keeps the file unchanged, without a question (rpm: no
.rpmnew; a changed config is still kept as.rpmsaveon removal).
Security
- The packaged unit sets
LimitCORE=0: the service writes no core dumps, which could
hold tokens, passwords and the TLS key. Before, only the soft limit was 0 and the
hard limit unlimited.
Install
Debian and Ubuntu: APT repository, see INSTALL.md.
Other systems: download the package or archive and SHA256SUMS, SHA256SUMS.asc and
release-signing-key.asc, then:
gpg --import release-signing-key.asc # 0B58 3E99 144D CD9B 5A34 D96B E52C 6D1E FB67 927B
gpg --verify SHA256SUMS.asc SHA256SUMS
sha256sum -c --ignore-missing SHA256SUMS