Merge branch 'master' into fix/env-avoid-quoted-values

This commit is contained in:
Brennan Kinney 2024-01-15 11:18:44 +13:00 committed by GitHub
commit 1f453726e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 805 additions and 429 deletions

1
.gitignore vendored
View File

@ -3,6 +3,7 @@
################################################# #################################################
.env .env
compose.override.yaml
docs/site/ docs/site/
docker-data/ docker-data/

View File

@ -6,8 +6,26 @@ All notable changes to this project will be documented in this file. The format
> **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes. > **Note**: Changes and additions listed here are contained in the `:edge` image tag. These changes may not be as stable as released changes.
### Features
- **Authentication with OIDC / OAuth 2.0** 🎉
- DMS now supports authentication via OAuth2 (_via `XOAUTH2` or `OAUTHBEARER` SASL mechanisms_) from capable services (_like Roundcube_).
- This does not replace the need for an `ACCOUNT_PROVISIONER` (`FILE` / `LDAP`), which is required for an account to receive or send mail.
- Successful authentication (_via Dovecot PassDB_) still requires an existing account (_lookup via Dovecot UserDB_).
- **MTA-STS** (_Optional support for mandatory outgoing TLS encryption_)
- If enabled and the outbound recipient has an MTA-STS policy set, TLS is mandatory for delivering to that recipient.
- Enable via the ENV `ENABLE_MTA_STS=1`
- Supported by major email service providers like Gmail, Yahoo and Outlook.
### Updates ### Updates
- **Tests**:
- Refactored mail sending ([#3747](https://github.com/docker-mailserver/docker-mailserver/pull/3747) & [#3772](https://github.com/docker-mailserver/docker-mailserver/pull/3772)):
- This change is a follow-up to [#3732](https://github.com/docker-mailserver/docker-mailserver/pull/3732) from DMS v13.2.
- `swaks` version is now the latest from Github releases instead of the Debian package.
- `_nc_wrapper`, `_send_mail` and related helpers expect the `.txt` filepath extension again.
- `sending.bash` helper methods were refactored to better integrate `swaks` and accommodate different usage contexts.
- `test/files/emails/existing/` files were removed similar to previous removal of SMTP auth files as they became redundant with `swaks`.
- **Internal:** - **Internal:**
- tests: Replace `wc -l` with `grep -c` ([#3752](https://github.com/docker-mailserver/docker-mailserver/pull/3752)) - tests: Replace `wc -l` with `grep -c` ([#3752](https://github.com/docker-mailserver/docker-mailserver/pull/3752))
- Postfix is now configured with `smtputf8_enable = no` in our default `main.cf` config (_instead of during container startup_). ([#3750](https://github.com/docker-mailserver/docker-mailserver/pull/3750)) - Postfix is now configured with `smtputf8_enable = no` in our default `main.cf` config (_instead of during container startup_). ([#3750](https://github.com/docker-mailserver/docker-mailserver/pull/3750))

View File

@ -321,46 +321,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/egavard"> <a href="https://github.com/kiliant">
<img src="https://avatars.githubusercontent.com/u/7823622?v=4" width="100;" alt="egavard"/> <img src="https://avatars.githubusercontent.com/u/5897310?v=4" width="100;" alt="kiliant"/>
<br /> <br />
<sub><b>egavard</b></sub> <sub><b>kiliant</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mathuin">
<img src="https://avatars.githubusercontent.com/u/221823?v=4" width="100;" alt="mathuin"/>
<br />
<sub><b>mathuin</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/dashohoxha">
<img src="https://avatars.githubusercontent.com/u/1495805?v=4" width="100;" alt="dashohoxha"/>
<br />
<sub><b>dashohoxha</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/jamebus">
<img src="https://avatars.githubusercontent.com/u/573734?v=4" width="100;" alt="jamebus"/>
<br />
<sub><b>jamebus</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/lukecyca">
<img src="https://avatars.githubusercontent.com/u/366484?v=4" width="100;" alt="lukecyca"/>
<br />
<sub><b>lukecyca</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/okainov">
<img src="https://avatars.githubusercontent.com/u/918446?v=4" width="100;" alt="okainov"/>
<br />
<sub><b>okainov</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -371,53 +335,68 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/kiliant"> <a href="https://github.com/okainov">
<img src="https://avatars.githubusercontent.com/u/5897310?v=4" width="100;" alt="kiliant"/> <img src="https://avatars.githubusercontent.com/u/918446?v=4" width="100;" alt="okainov"/>
<br /> <br />
<sub><b>kiliant</b></sub> <sub><b>okainov</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/m-schmoock"> <a href="https://github.com/lukecyca">
<img src="https://avatars.githubusercontent.com/u/4090425?v=4" width="100;" alt="m-schmoock"/> <img src="https://avatars.githubusercontent.com/u/366484?v=4" width="100;" alt="lukecyca"/>
<br /> <br />
<sub><b>m-schmoock</b></sub> <sub><b>lukecyca</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/mjung">
<img src="https://avatars.githubusercontent.com/u/1105431?v=4" width="100;" alt="mjung"/>
<br />
<sub><b>mjung</b></sub>
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
<td align="center"> <td align="center">
<a href="https://github.com/VanVan"> <a href="https://github.com/jsonn">
<img src="https://avatars.githubusercontent.com/u/388581?v=4" width="100;" alt="VanVan"/> <img src="https://avatars.githubusercontent.com/u/296817?v=4" width="100;" alt="jsonn"/>
<br /> <br />
<sub><b>VanVan</b></sub> <sub><b>jsonn</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/andreasgerstmayr"> <a href="https://github.com/jamebus">
<img src="https://avatars.githubusercontent.com/u/538011?v=4" width="100;" alt="andreasgerstmayr"/> <img src="https://avatars.githubusercontent.com/u/573734?v=4" width="100;" alt="jamebus"/>
<br /> <br />
<sub><b>andreasgerstmayr</b></sub> <sub><b>jamebus</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/davidszp"> <a href="https://github.com/dashohoxha">
<img src="https://avatars.githubusercontent.com/u/15107452?v=4" width="100;" alt="davidszp"/> <img src="https://avatars.githubusercontent.com/u/1495805?v=4" width="100;" alt="dashohoxha"/>
<br /> <br />
<sub><b>davidszp</b></sub> <sub><b>dashohoxha</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/kamuri"> <a href="https://github.com/mathuin">
<img src="https://avatars.githubusercontent.com/u/2777769?v=4" width="100;" alt="kamuri"/> <img src="https://avatars.githubusercontent.com/u/221823?v=4" width="100;" alt="mathuin"/>
<br /> <br />
<sub><b>kamuri</b></sub> <sub><b>mathuin</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/egavard">
<img src="https://avatars.githubusercontent.com/u/7823622?v=4" width="100;" alt="egavard"/>
<br />
<sub><b>egavard</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/weo">
<img src="https://avatars.githubusercontent.com/u/239722?v=4" width="100;" alt="weo"/>
<br />
<sub><b>weo</b></sub>
</a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/Zehir">
<img src="https://avatars.githubusercontent.com/u/845225?v=4" width="100;" alt="Zehir"/>
<br />
<sub><b>Zehir</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -428,18 +407,46 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/Zehir"> <a href="https://github.com/kamuri">
<img src="https://avatars.githubusercontent.com/u/845225?v=4" width="100;" alt="Zehir"/> <img src="https://avatars.githubusercontent.com/u/2777769?v=4" width="100;" alt="kamuri"/>
<br /> <br />
<sub><b>Zehir</b></sub> <sub><b>kamuri</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/davidszp">
<img src="https://avatars.githubusercontent.com/u/15107452?v=4" width="100;" alt="davidszp"/>
<br />
<sub><b>davidszp</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/andreasgerstmayr">
<img src="https://avatars.githubusercontent.com/u/538011?v=4" width="100;" alt="andreasgerstmayr"/>
<br />
<sub><b>andreasgerstmayr</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/VanVan">
<img src="https://avatars.githubusercontent.com/u/388581?v=4" width="100;" alt="VanVan"/>
<br />
<sub><b>VanVan</b></sub>
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
<td align="center"> <td align="center">
<a href="https://github.com/weo"> <a href="https://github.com/mjung">
<img src="https://avatars.githubusercontent.com/u/239722?v=4" width="100;" alt="weo"/> <img src="https://avatars.githubusercontent.com/u/1105431?v=4" width="100;" alt="mjung"/>
<br /> <br />
<sub><b>weo</b></sub> <sub><b>mjung</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/m-schmoock">
<img src="https://avatars.githubusercontent.com/u/4090425?v=4" width="100;" alt="m-schmoock"/>
<br />
<sub><b>m-schmoock</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -469,15 +476,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>Starbix</b></sub> <sub><b>Starbix</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/citec"> <a href="https://github.com/citec">
<img src="https://avatars.githubusercontent.com/u/4775008?v=4" width="100;" alt="citec"/> <img src="https://avatars.githubusercontent.com/u/4775008?v=4" width="100;" alt="citec"/>
<br /> <br />
<sub><b>citec</b></sub> <sub><b>citec</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/yajo"> <a href="https://github.com/yajo">
<img src="https://avatars.githubusercontent.com/u/973709?v=4" width="100;" alt="yajo"/> <img src="https://avatars.githubusercontent.com/u/973709?v=4" width="100;" alt="yajo"/>
@ -492,13 +499,6 @@ Thanks goes to these wonderful people ✨
<sub><b>analogue</b></sub> <sub><b>analogue</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/MakerMatrix">
<img src="https://avatars.githubusercontent.com/u/52144433?v=4" width="100;" alt="MakerMatrix"/>
<br />
<sub><b>MakerMatrix</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/Rubytastic2"> <a href="https://github.com/Rubytastic2">
<img src="https://avatars.githubusercontent.com/u/21036612?v=4" width="100;" alt="Rubytastic2"/> <img src="https://avatars.githubusercontent.com/u/21036612?v=4" width="100;" alt="Rubytastic2"/>
@ -514,10 +514,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/jsonn"> <a href="https://github.com/MakerMatrix">
<img src="https://avatars.githubusercontent.com/u/296817?v=4" width="100;" alt="jsonn"/> <img src="https://avatars.githubusercontent.com/u/52144433?v=4" width="100;" alt="MakerMatrix"/>
<br /> <br />
<sub><b>jsonn</b></sub> <sub><b>MakerMatrix</b></sub>
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
@ -642,26 +642,33 @@ Thanks goes to these wonderful people ✨
<sub><b>yogo1212</b></sub> <sub><b>yogo1212</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/mpanneck">
<img src="https://avatars.githubusercontent.com/u/37032012?v=4" width="100;" alt="mpanneck"/>
<br />
<sub><b>mpanneck</b></sub>
</a>
</td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/willtho89"> <a href="https://github.com/willtho89">
<img src="https://avatars.githubusercontent.com/u/4933503?v=4" width="100;" alt="willtho89"/> <img src="https://avatars.githubusercontent.com/u/4933503?v=4" width="100;" alt="willtho89"/>
<br /> <br />
<sub><b>willtho89</b></sub> <sub><b>willtho89</b></sub>
</a> </a>
</td></tr>
<tr>
<td align="center">
<a href="https://github.com/mpanneck">
<img src="https://avatars.githubusercontent.com/u/37032012?v=4" width="100;" alt="mpanneck"/>
<br />
<sub><b>mpanneck</b></sub>
</a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/ubenmackin"> <a href="https://github.com/aminvakil">
<img src="https://avatars.githubusercontent.com/u/11615536?v=4" width="100;" alt="ubenmackin"/> <img src="https://avatars.githubusercontent.com/u/12948692?v=4" width="100;" alt="aminvakil"/>
<br /> <br />
<sub><b>ubenmackin</b></sub> <sub><b>aminvakil</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elbracht">
<img src="https://avatars.githubusercontent.com/u/2912000?v=4" width="100;" alt="elbracht"/>
<br />
<sub><b>elbracht</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -679,17 +686,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/aminvakil"> <a href="https://github.com/ubenmackin">
<img src="https://avatars.githubusercontent.com/u/12948692?v=4" width="100;" alt="aminvakil"/> <img src="https://avatars.githubusercontent.com/u/11615536?v=4" width="100;" alt="ubenmackin"/>
<br /> <br />
<sub><b>aminvakil</b></sub> <sub><b>ubenmackin</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/elbracht">
<img src="https://avatars.githubusercontent.com/u/2912000?v=4" width="100;" alt="elbracht"/>
<br />
<sub><b>elbracht</b></sub>
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
@ -780,10 +780,17 @@ Thanks goes to these wonderful people ✨
</td></tr> </td></tr>
<tr> <tr>
<td align="center"> <td align="center">
<a href="https://github.com/fl42"> <a href="https://github.com/jamesfryer">
<img src="https://avatars.githubusercontent.com/u/46161216?v=4" width="100;" alt="fl42"/> <img src="https://avatars.githubusercontent.com/u/2470760?v=4" width="100;" alt="jamesfryer"/>
<br /> <br />
<sub><b>fl42</b></sub> <sub><b>jamesfryer</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/eltociear">
<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="100;" alt="eltociear"/>
<br />
<sub><b>eltociear</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -801,17 +808,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/jamesfryer"> <a href="https://github.com/fl42">
<img src="https://avatars.githubusercontent.com/u/2470760?v=4" width="100;" alt="jamesfryer"/> <img src="https://avatars.githubusercontent.com/u/46161216?v=4" width="100;" alt="fl42"/>
<br /> <br />
<sub><b>jamesfryer</b></sub> <sub><b>fl42</b></sub>
</a>
</td>
<td align="center">
<a href="https://github.com/eltociear">
<img src="https://avatars.githubusercontent.com/u/22633385?v=4" width="100;" alt="eltociear"/>
<br />
<sub><b>eltociear</b></sub>
</a> </a>
</td> </td>
<td align="center"> <td align="center">
@ -944,10 +944,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/0xflotus"> <a href="https://github.com/nilshoell">
<img src="https://avatars.githubusercontent.com/u/26602940?v=4" width="100;" alt="0xflotus"/> <img src="https://avatars.githubusercontent.com/u/33981934?v=4" width="100;" alt="nilshoell"/>
<br /> <br />
<sub><b>0xflotus</b></sub> <sub><b>nilshoell</b></sub>
</a> </a>
</td></tr> </td></tr>
<tr> <tr>
@ -1388,6 +1388,13 @@ Thanks goes to these wonderful people ✨
<sub><b>mchamplain</b></sub> <sub><b>mchamplain</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/0xflotus">
<img src="https://avatars.githubusercontent.com/u/26602940?v=4" width="100;" alt="0xflotus"/>
<br />
<sub><b>0xflotus</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/auchri"> <a href="https://github.com/auchri">
<img src="https://avatars.githubusercontent.com/u/5092164?v=4" width="100;" alt="auchri"/> <img src="https://avatars.githubusercontent.com/u/5092164?v=4" width="100;" alt="auchri"/>
@ -1415,15 +1422,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>damianmoore</b></sub> <sub><b>damianmoore</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/espitall"> <a href="https://github.com/espitall">
<img src="https://avatars.githubusercontent.com/u/1910925?v=4" width="100;" alt="espitall"/> <img src="https://avatars.githubusercontent.com/u/1910925?v=4" width="100;" alt="espitall"/>
<br /> <br />
<sub><b>espitall</b></sub> <sub><b>espitall</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/dkarski"> <a href="https://github.com/dkarski">
<img src="https://avatars.githubusercontent.com/u/17147149?v=4" width="100;" alt="dkarski"/> <img src="https://avatars.githubusercontent.com/u/17147149?v=4" width="100;" alt="dkarski"/>
@ -1458,15 +1465,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>mazzz1y</b></sub> <sub><b>mazzz1y</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/aydodo"> <a href="https://github.com/aydodo">
<img src="https://avatars.githubusercontent.com/u/5312040?v=4" width="100;" alt="aydodo"/> <img src="https://avatars.githubusercontent.com/u/5312040?v=4" width="100;" alt="aydodo"/>
<br /> <br />
<sub><b>aydodo</b></sub> <sub><b>aydodo</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/vedtam"> <a href="https://github.com/vedtam">
<img src="https://avatars.githubusercontent.com/u/4981592?v=4" width="100;" alt="vedtam"/> <img src="https://avatars.githubusercontent.com/u/4981592?v=4" width="100;" alt="vedtam"/>
@ -1501,15 +1508,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>ErikEngerd</b></sub> <sub><b>ErikEngerd</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/huncode"> <a href="https://github.com/huncode">
<img src="https://avatars.githubusercontent.com/u/1650008?v=4" width="100;" alt="huncode"/> <img src="https://avatars.githubusercontent.com/u/1650008?v=4" width="100;" alt="huncode"/>
<br /> <br />
<sub><b>huncode</b></sub> <sub><b>huncode</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/felixn"> <a href="https://github.com/felixn">
<img src="https://avatars.githubusercontent.com/u/221502?v=4" width="100;" alt="felixn"/> <img src="https://avatars.githubusercontent.com/u/221502?v=4" width="100;" alt="felixn"/>
@ -1544,15 +1551,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>20th</b></sub> <sub><b>20th</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/2b"> <a href="https://github.com/2b">
<img src="https://avatars.githubusercontent.com/u/829041?v=4" width="100;" alt="2b"/> <img src="https://avatars.githubusercontent.com/u/829041?v=4" width="100;" alt="2b"/>
<br /> <br />
<sub><b>2b</b></sub> <sub><b>2b</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/askz"> <a href="https://github.com/askz">
<img src="https://avatars.githubusercontent.com/u/854038?v=4" width="100;" alt="askz"/> <img src="https://avatars.githubusercontent.com/u/854038?v=4" width="100;" alt="askz"/>
@ -1587,15 +1594,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>alexanderneu</b></sub> <sub><b>alexanderneu</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/ch3sh1r"> <a href="https://github.com/ch3sh1r">
<img src="https://avatars.githubusercontent.com/u/441777?v=4" width="100;" alt="ch3sh1r"/> <img src="https://avatars.githubusercontent.com/u/441777?v=4" width="100;" alt="ch3sh1r"/>
<br /> <br />
<sub><b>ch3sh1r</b></sub> <sub><b>ch3sh1r</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/eglia"> <a href="https://github.com/eglia">
<img src="https://avatars.githubusercontent.com/u/17555261?v=4" width="100;" alt="eglia"/> <img src="https://avatars.githubusercontent.com/u/17555261?v=4" width="100;" alt="eglia"/>
@ -1630,15 +1637,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>MrFreezeex</b></sub> <sub><b>MrFreezeex</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/arunvc"> <a href="https://github.com/arunvc">
<img src="https://avatars.githubusercontent.com/u/9069988?v=4" width="100;" alt="arunvc"/> <img src="https://avatars.githubusercontent.com/u/9069988?v=4" width="100;" alt="arunvc"/>
<br /> <br />
<sub><b>arunvc</b></sub> <sub><b>arunvc</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/astrocket"> <a href="https://github.com/astrocket">
<img src="https://avatars.githubusercontent.com/u/18032062?v=4" width="100;" alt="astrocket"/> <img src="https://avatars.githubusercontent.com/u/18032062?v=4" width="100;" alt="astrocket"/>
@ -1673,15 +1680,22 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>crash7</b></sub> <sub><b>crash7</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/fkefer"> <a href="https://github.com/fkefer">
<img src="https://avatars.githubusercontent.com/u/1140674?v=4" width="100;" alt="fkefer"/> <img src="https://avatars.githubusercontent.com/u/1140674?v=4" width="100;" alt="fkefer"/>
<br /> <br />
<sub><b>fkefer</b></sub> <sub><b>fkefer</b></sub>
</a> </a>
</td></tr> </td>
<tr> <td align="center">
<a href="https://github.com/KCrawley">
<img src="https://avatars.githubusercontent.com/u/60195478?v=4" width="100;" alt="KCrawley"/>
<br />
<sub><b>KCrawley</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/khuedoan"> <a href="https://github.com/khuedoan">
<img src="https://avatars.githubusercontent.com/u/27996771?v=4" width="100;" alt="khuedoan"/> <img src="https://avatars.githubusercontent.com/u/27996771?v=4" width="100;" alt="khuedoan"/>
@ -1709,7 +1723,8 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>linhandev</b></sub> <sub><b>linhandev</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/luke-"> <a href="https://github.com/luke-">
<img src="https://avatars.githubusercontent.com/u/4736168?v=4" width="100;" alt="luke-"/> <img src="https://avatars.githubusercontent.com/u/4736168?v=4" width="100;" alt="luke-"/>
@ -1723,8 +1738,7 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>LucidityCrash</b></sub> <sub><b>LucidityCrash</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/MadsRC"> <a href="https://github.com/MadsRC">
<img src="https://avatars.githubusercontent.com/u/2797266?v=4" width="100;" alt="MadsRC"/> <img src="https://avatars.githubusercontent.com/u/2797266?v=4" width="100;" alt="MadsRC"/>
@ -1752,7 +1766,8 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>dragetd</b></sub> <sub><b>dragetd</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/michaeljensen"> <a href="https://github.com/michaeljensen">
<img src="https://avatars.githubusercontent.com/u/3026633?v=4" width="100;" alt="michaeljensen"/> <img src="https://avatars.githubusercontent.com/u/3026633?v=4" width="100;" alt="michaeljensen"/>
@ -1766,8 +1781,7 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>exhuma</b></sub> <sub><b>exhuma</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/milas"> <a href="https://github.com/milas">
<img src="https://avatars.githubusercontent.com/u/841263?v=4" width="100;" alt="milas"/> <img src="https://avatars.githubusercontent.com/u/841263?v=4" width="100;" alt="milas"/>
@ -1795,7 +1809,8 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>mpldr</b></sub> <sub><b>mpldr</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/naveensrinivasan"> <a href="https://github.com/naveensrinivasan">
<img src="https://avatars.githubusercontent.com/u/172697?v=4" width="100;" alt="naveensrinivasan"/> <img src="https://avatars.githubusercontent.com/u/172697?v=4" width="100;" alt="naveensrinivasan"/>
@ -1809,8 +1824,7 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>neuralp</b></sub> <sub><b>neuralp</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/radicand"> <a href="https://github.com/radicand">
<img src="https://avatars.githubusercontent.com/u/673843?v=4" width="100;" alt="radicand"/> <img src="https://avatars.githubusercontent.com/u/673843?v=4" width="100;" alt="radicand"/>
@ -1818,13 +1832,6 @@ Thanks goes to these wonderful people ✨
<sub><b>radicand</b></sub> <sub><b>radicand</b></sub>
</a> </a>
</td> </td>
<td align="center">
<a href="https://github.com/nilshoell">
<img src="https://avatars.githubusercontent.com/u/33981934?v=4" width="100;" alt="nilshoell"/>
<br />
<sub><b>nilshoell</b></sub>
</a>
</td>
<td align="center"> <td align="center">
<a href="https://github.com/frugan-dev"> <a href="https://github.com/frugan-dev">
<img src="https://avatars.githubusercontent.com/u/7957714?v=4" width="100;" alt="frugan-dev"/> <img src="https://avatars.githubusercontent.com/u/7957714?v=4" width="100;" alt="frugan-dev"/>
@ -1845,15 +1852,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>glandais</b></sub> <sub><b>glandais</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/GiovanH"> <a href="https://github.com/GiovanH">
<img src="https://avatars.githubusercontent.com/u/6759280?v=4" width="100;" alt="GiovanH"/> <img src="https://avatars.githubusercontent.com/u/6759280?v=4" width="100;" alt="GiovanH"/>
<br /> <br />
<sub><b>GiovanH</b></sub> <sub><b>GiovanH</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/harryyoud"> <a href="https://github.com/harryyoud">
<img src="https://avatars.githubusercontent.com/u/10576381?v=4" width="100;" alt="harryyoud"/> <img src="https://avatars.githubusercontent.com/u/10576381?v=4" width="100;" alt="harryyoud"/>
@ -1888,15 +1895,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>jcalfee</b></sub> <sub><b>jcalfee</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/mivek"> <a href="https://github.com/mivek">
<img src="https://avatars.githubusercontent.com/u/9912558?v=4" width="100;" alt="mivek"/> <img src="https://avatars.githubusercontent.com/u/9912558?v=4" width="100;" alt="mivek"/>
<br /> <br />
<sub><b>mivek</b></sub> <sub><b>mivek</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/init-js"> <a href="https://github.com/init-js">
<img src="https://avatars.githubusercontent.com/u/1110751?v=4" width="100;" alt="init-js"/> <img src="https://avatars.githubusercontent.com/u/1110751?v=4" width="100;" alt="init-js"/>
@ -1931,15 +1938,15 @@ Thanks goes to these wonderful people ✨
<br /> <br />
<sub><b>jmccl</b></sub> <sub><b>jmccl</b></sub>
</a> </a>
</td> </td></tr>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/jurekbarth"> <a href="https://github.com/jurekbarth">
<img src="https://avatars.githubusercontent.com/u/4249843?v=4" width="100;" alt="jurekbarth"/> <img src="https://avatars.githubusercontent.com/u/4249843?v=4" width="100;" alt="jurekbarth"/>
<br /> <br />
<sub><b>jurekbarth</b></sub> <sub><b>jurekbarth</b></sub>
</a> </a>
</td></tr> </td>
<tr>
<td align="center"> <td align="center">
<a href="https://github.com/JOduMonT"> <a href="https://github.com/JOduMonT">
<img src="https://avatars.githubusercontent.com/u/5204724?v=4" width="100;" alt="JOduMonT"/> <img src="https://avatars.githubusercontent.com/u/5204724?v=4" width="100;" alt="JOduMonT"/>
@ -1962,10 +1969,10 @@ Thanks goes to these wonderful people ✨
</a> </a>
</td> </td>
<td align="center"> <td align="center">
<a href="https://github.com/KCrawley"> <a href="https://github.com/thechubbypanda">
<img src="https://avatars.githubusercontent.com/u/60195478?v=4" width="100;" alt="KCrawley"/> <img src="https://avatars.githubusercontent.com/u/33595996?v=4" width="100;" alt="thechubbypanda"/>
<br /> <br />
<sub><b>KCrawley</b></sub> <sub><b>thechubbypanda</b></sub>
</a> </a>
</td></tr> </td></tr>
</table> </table>

View File

@ -108,6 +108,13 @@ EOF
COPY target/rspamd/local.d/ /etc/rspamd/local.d/ COPY target/rspamd/local.d/ /etc/rspamd/local.d/
COPY target/rspamd/scores.d/* /etc/rspamd/scores.d/ COPY target/rspamd/scores.d/* /etc/rspamd/scores.d/
# -----------------------------------------------
# --- OAUTH2 ------------------------------------
# -----------------------------------------------
COPY target/dovecot/auth-oauth2.conf.ext /etc/dovecot/conf.d
COPY target/dovecot/dovecot-oauth2.conf.ext /etc/dovecot
# ----------------------------------------------- # -----------------------------------------------
# --- LDAP & SpamAssassin's Cron ---------------- # --- LDAP & SpamAssassin's Cron ----------------
# ----------------------------------------------- # -----------------------------------------------
@ -192,6 +199,15 @@ COPY target/opendmarc/opendmarc.conf /etc/opendmarc.conf
COPY target/opendmarc/default-opendmarc /etc/default/opendmarc COPY target/opendmarc/default-opendmarc /etc/default/opendmarc
COPY target/opendmarc/ignore.hosts /etc/opendmarc/ignore.hosts COPY target/opendmarc/ignore.hosts /etc/opendmarc/ignore.hosts
# --------------------------------------------------
# --- postfix-mta-sts-daemon -----------------------
# --------------------------------------------------
COPY target/mta-sts-daemon/mta-sts-daemon.yml /etc/mta-sts-daemon.yml
RUN <<EOF
mkdir /var/run/mta-sts
chown -R _mta-sts:root /var/run/mta-sts
EOF
# -------------------------------------------------- # --------------------------------------------------
# --- Fetchmail, Getmail, Postfix & Let'sEncrypt --- # --- Fetchmail, Getmail, Postfix & Let'sEncrypt ---
# -------------------------------------------------- # --------------------------------------------------

View File

@ -48,3 +48,4 @@ If you have issues, please search through [the documentation][documentation::web
- Support for [LetsEncrypt](https://letsencrypt.org/), manual and self-signed certificates - Support for [LetsEncrypt](https://letsencrypt.org/), manual and self-signed certificates
- A [setup script](https://docker-mailserver.github.io/docker-mailserver/latest/config/setup.sh) for easy configuration and maintenance - A [setup script](https://docker-mailserver.github.io/docker-mailserver/latest/config/setup.sh) for easy configuration and maintenance
- SASLauthd with LDAP authentication - SASLauthd with LDAP authentication
- OAuth2 authentication (_via `XOAUTH2` or `OAUTHBEARER` SASL mechanisms_)

View File

@ -0,0 +1,69 @@
---
title: 'Advanced | Basic OAuth2 Authentication'
---
## Introduction
!!! warning "This is only a supplement to the existing account provisioners"
Accounts must still be managed via the configured [`ACCOUNT_PROVISIONER`][env::account-provisioner] (FILE or LDAP).
Reasoning for this can be found in [#3480][gh-pr::oauth2]. Future iterations on this feature may allow it to become a full account provisioner.
[gh-pr::oauth2]: https://github.com/docker-mailserver/docker-mailserver/pull/3480
[env::account-provisioner]: ../environment.md#account_provisioner
The present OAuth2 support provides the capability for 3rd-party applications such as Roundcube to authenticate with DMS (dovecot) by using a token obtained from an OAuth2 provider, instead of passing passwords around.
## Example (Authentik & Roundcube)
This example assumes you have:
- A working DMS server set up
- An Authentik server set up ([documentation](https://goauthentik.io/docs/installation/))
- A Roundcube server set up (either [docker](https://hub.docker.com/r/roundcube/roundcubemail/) or [bare metal](https://github.com/roundcube/roundcubemail/wiki/Installation))
!!! example "Setup Instructions"
=== "1. Docker Mailserver"
Edit the following values in `mailserver.env`:
```env
# -----------------------------------------------
# --- OAUTH2 Section ----------------------------
# -----------------------------------------------
# empty => OAUTH2 authentication is disabled
# 1 => OAUTH2 authentication is enabled
ENABLE_OAUTH2=1
# Specify the user info endpoint URL of the oauth2 provider
OAUTH2_INTROSPECTION_URL=https://authentik.example.com/application/o/userinfo/
```
=== "2. Authentik"
1. Create a new OAuth2 provider
2. Note the client id and client secret
3. Set the allowed redirect url to the equivalent of `https://roundcube.example.com/index.php/login/oauth` for your RoundCube instance.
=== "3. Roundcube"
Add the following to `oauth2.inc.php` ([documentation](https://github.com/roundcube/roundcubemail/wiki/Configuration)):
```php
$config['oauth_provider'] = 'generic';
$config['oauth_provider_name'] = 'Authentik';
$config['oauth_client_id'] = '<insert client id here>';
$config['oauth_client_secret'] = '<insert client secret here>';
$config['oauth_auth_uri'] = 'https://authentik.example.com/application/o/authorize/';
$config['oauth_token_uri'] = 'https://authentik.example.com/application/o/token/';
$config['oauth_identity_uri'] = 'https://authentik.example.com/application/o/userinfo/';
// Optional: disable SSL certificate check on HTTP requests to OAuth server. For possible values, see:
// http://docs.guzzlephp.org/en/stable/request-options.html#verify
$config['oauth_verify_peer'] = false;
$config['oauth_scope'] = 'email openid profile';
$config['oauth_identity_fields'] = ['email'];
// Boolean: automatically redirect to OAuth login when opening Roundcube without a valid session
$config['oauth_login_redirect'] = false;
```

View File

@ -0,0 +1,30 @@
---
title: 'Best practices | MTA-STS'
hide:
- toc # Hide Table of Contents for this page
---
MTA-STS is an optional mechanism for a domain to signal support for STARTTLS.
- It can be used to prevent man-in-the-middle-attacks from hiding STARTTLS support that would force DMS to send outbound mail through an insecure connection.
- MTA-STS is an alternative to DANE without the need of DNSSEC.
- MTA-STS is supported by some of the biggest mail providers like Google Mail and Outlook.
## Supporting MTA-STS for outbound mail
Enable this feature via the ENV setting [`ENABLE_MTA_STS=1`](../environment.md#enable_mta_sts).
!!! warning "If you have configured DANE"
Enabling MTA-STS will by default override DANE if both are configured for a domain.
This can be partially addressed by configuring a dane-only policy resolver before the MTA-STS entry in `smtp_tls_policy_maps`. See the [`postfix-mta-sts-resolver` documentation][postfix-mta-sts-resolver::dane] for further details.
[postfix-mta-sts-resolver::dane]: https://github.com/Snawoot/postfix-mta-sts-resolver#warning-mta-sts-policy-overrides-dane-tls-authentication
## Supporting MTA-STS for inbound mail
While this feature in DMS supports ensuring STARTTLS is used when mail is sent to another mail server, you may setup similar for mail servers sending mail to DMS.
This requires configuring your DNS and hosting the MTA-STS policy file via a webserver. A good introduction can be found on [dmarcian.com](https://dmarcian.com/mta-sts/).

View File

@ -54,7 +54,15 @@ The Group ID assigned to the static vmail group for `/var/mail` (_Mail storage m
Configures the provisioning source of user accounts (including aliases) for user queries and authentication by services managed by DMS (_Postfix and Dovecot_). Configures the provisioning source of user accounts (including aliases) for user queries and authentication by services managed by DMS (_Postfix and Dovecot_).
User provisioning via OIDC is planned for the future, see [this tracking issue](https://github.com/docker-mailserver/docker-mailserver/issues/2713). !!! tip "OAuth2 Support"
Presently DMS supports OAuth2 only as an supplementary authentication method.
- A third-party service must provide a valid token for the user which Dovecot validates with the authentication service provider. To enable this feature reference the [OAuth2 configuration example guide][docs::auth::oauth2-config-guide].
- User accounts must be provisioned to receive mail via one of the supported `ACCOUNT_PROVISIONER` providers.
- User provisioning via OIDC is planned for the future, see [this tracking issue](https://github.com/docker-mailserver/docker-mailserver/issues/2713).
[docs::auth::oauth2-config-guide]: ./advanced/auth-oauth2.md
- **empty** => use FILE - **empty** => use FILE
- LDAP => use LDAP authentication - LDAP => use LDAP authentication
@ -108,6 +116,15 @@ This enables DNS block lists in _Postscreen_. If you want to know which lists we
- **0** => DNS block lists are disabled - **0** => DNS block lists are disabled
- 1 => DNS block lists are enabled - 1 => DNS block lists are enabled
##### ENABLE_MTA_STS
Enables MTA-STS support for outbound mail.
- **0** => Disabled
- 1 => Enabled
See [MTA-STS](best-practices/mta-sts.md) for further explanation.
##### ENABLE_OPENDKIM ##### ENABLE_OPENDKIM
Enables the OpenDKIM service. Enables the OpenDKIM service.
@ -716,10 +733,20 @@ Enable or disable `getmail`.
- **5** => `getmail` The number of minutes for the interval. Min: 1; Max: 30; Default: 5. - **5** => `getmail` The number of minutes for the interval. Min: 1; Max: 30; Default: 5.
#### OAUTH2
##### ENABLE_OAUTH2
- **empty** => OAUTH2 authentication is disabled
- 1 => OAUTH2 authentication is enabled
##### OAUTH2_INTROSPECTION_URL
- => Specify the user info endpoint URL of the oauth2 provider (_eg: `https://oauth2.example.com/userinfo/`_)
#### LDAP #### LDAP
##### LDAP_START_TLS ##### LDAP_START_TLS
- **empty** => no - **empty** => no

View File

@ -122,8 +122,9 @@ nav:
- 'Environment Variables': config/environment.md - 'Environment Variables': config/environment.md
- 'User Management': config/user-management.md - 'User Management': config/user-management.md
- 'Best Practices': - 'Best Practices':
- 'DKIM, DMARC & SPF': config/best-practices/dkim_dmarc_spf.md
- 'Auto-discovery': config/best-practices/autodiscover.md - 'Auto-discovery': config/best-practices/autodiscover.md
- 'DKIM, DMARC & SPF': config/best-practices/dkim_dmarc_spf.md
- 'MTA-STS': config/best-practices/mta-sts.md
- 'Security': - 'Security':
- 'Understanding the Ports': config/security/understanding-the-ports.md - 'Understanding the Ports': config/security/understanding-the-ports.md
- 'SSL/TLS': config/security/ssl.md - 'SSL/TLS': config/security/ssl.md
@ -142,6 +143,7 @@ nav:
- 'Postfix': config/advanced/override-defaults/postfix.md - 'Postfix': config/advanced/override-defaults/postfix.md
- 'Modifications via Script': config/advanced/override-defaults/user-patches.md - 'Modifications via Script': config/advanced/override-defaults/user-patches.md
- 'LDAP Authentication': config/advanced/auth-ldap.md - 'LDAP Authentication': config/advanced/auth-ldap.md
- 'OAuth2 Authentication': config/advanced/auth-oauth2.md
- 'Email Filtering with Sieve': config/advanced/mail-sieve.md - 'Email Filtering with Sieve': config/advanced/mail-sieve.md
- 'Email Gathering with Fetchmail': config/advanced/mail-fetchmail.md - 'Email Gathering with Fetchmail': config/advanced/mail-fetchmail.md
- 'Email Gathering with Getmail': config/advanced/mail-getmail.md - 'Email Gathering with Getmail': config/advanced/mail-getmail.md

View File

@ -354,6 +354,12 @@ POSTFIX_REJECT_UNKNOWN_CLIENT_HOSTNAME=0
# Note: More details at http://www.postfix.org/postconf.5.html#inet_protocols # Note: More details at http://www.postfix.org/postconf.5.html#inet_protocols
POSTFIX_INET_PROTOCOLS=all POSTFIX_INET_PROTOCOLS=all
# Enables MTA-STS support for outbound mail.
# More details: https://docker-mailserver.github.io/docker-mailserver/latest/config/advanced/mail-mta-sts/
# - **0** ==> MTA-STS disabled
# - 1 => MTA-STS enabled
ENABLE_MTA_STS=0
# Choose TCP/IP protocols for dovecot to use # Choose TCP/IP protocols for dovecot to use
# **all** => Listen on all interfaces # **all** => Listen on all interfaces
# ipv4 => Listen only on IPv4 interfaces. Most likely you want this behind Docker. # ipv4 => Listen only on IPv4 interfaces. Most likely you want this behind Docker.
@ -422,6 +428,18 @@ ENABLE_GETMAIL=0
# The number of minutes for the interval. Min: 1; Max: 30. # The number of minutes for the interval. Min: 1; Max: 30.
GETMAIL_POLL=5 GETMAIL_POLL=5
# -----------------------------------------------
# --- OAUTH2 Section ----------------------------
# -----------------------------------------------
# empty => OAUTH2 authentication is disabled
# 1 => OAUTH2 authentication is enabled
ENABLE_OAUTH2=
# Specify the user info endpoint URL of the oauth2 provider
# Example: https://oauth2.example.com/userinfo/
OAUTH2_INTROSPECTION_URL=
# ----------------------------------------------- # -----------------------------------------------
# --- LDAP Section ------------------------------ # --- LDAP Section ------------------------------
# ----------------------------------------------- # -----------------------------------------------

View File

@ -123,6 +123,7 @@ auth_mechanisms = plain login
#!include auth-sql.conf.ext #!include auth-sql.conf.ext
#!include auth-ldap.conf.ext #!include auth-ldap.conf.ext
!include auth-passwdfile.inc !include auth-passwdfile.inc
#!include auth-oauth2.conf.ext
#!include auth-checkpassword.conf.ext #!include auth-checkpassword.conf.ext
#!include auth-vpopmail.conf.ext #!include auth-vpopmail.conf.ext
#!include auth-static.conf.ext #!include auth-static.conf.ext

View File

@ -0,0 +1,7 @@
auth_mechanisms = $auth_mechanisms oauthbearer xoauth2
passdb {
driver = oauth2
mechanisms = xoauth2 oauthbearer
args = /etc/dovecot/dovecot-oauth2.conf.ext
}

View File

@ -0,0 +1,4 @@
introspection_url =
# Dovecot defaults:
introspection_mode = auth
username_attribute = email

View File

@ -0,0 +1,7 @@
# Docs: https://github.com/Snawoot/postfix-mta-sts-resolver/blob/master/man/mta-sts-daemon.yml.5.adoc
path: /var/run/mta-sts/daemon.sock
mode: 0666
cache:
type: sqlite
options:
filename: "/var/lib/mta-sts/cache.db"

View File

@ -68,7 +68,7 @@ function _install_packages() {
) )
POSTFIX_PACKAGES=( POSTFIX_PACKAGES=(
pflogsumm postgrey postfix-ldap pflogsumm postgrey postfix-ldap postfix-mta-sts-resolver
postfix-pcre postfix-policyd-spf-python postsrsd postfix-pcre postfix-policyd-spf-python postsrsd
) )
@ -80,7 +80,7 @@ function _install_packages() {
# `bind9-dnsutils` provides the `dig` command # `bind9-dnsutils` provides the `dig` command
# `iputils-ping` provides the `ping` command # `iputils-ping` provides the `ping` command
DEBUG_PACKAGES=( DEBUG_PACKAGES=(
bind9-dnsutils iputils-ping less nano swaks bind9-dnsutils iputils-ping less nano
) )
apt-get "${QUIET}" --no-install-recommends install \ apt-get "${QUIET}" --no-install-recommends install \
@ -192,7 +192,15 @@ function _install_getmail() {
function _install_utils() { function _install_utils() {
_log 'debug' 'Installing utils sourced from Github' _log 'debug' 'Installing utils sourced from Github'
_log 'trace' 'Installing jaq'
curl -sL "https://github.com/01mf02/jaq/releases/latest/download/jaq-v1.2.0-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq && chmod +x /usr/bin/jaq curl -sL "https://github.com/01mf02/jaq/releases/latest/download/jaq-v1.2.0-$(uname -m)-unknown-linux-gnu" -o /usr/bin/jaq && chmod +x /usr/bin/jaq
_log 'trace' 'Installing swaks'
local SWAKS_VERSION='20240103.0'
local SWAKS_RELEASE="swaks-${SWAKS_VERSION}"
curl -sSfL "https://github.com/jetmore/swaks/releases/download/v${SWAKS_VERSION}/${SWAKS_RELEASE}.tar.gz" | tar -xz
mv "${SWAKS_RELEASE}/swaks" /usr/local/bin
rm -r "${SWAKS_RELEASE}"
} }
function _remove_data_after_package_installations() { function _remove_data_after_package_installations() {

View File

@ -71,6 +71,11 @@ function _register_functions() {
;; ;;
esac esac
if [[ ${ENABLE_OAUTH2} -eq 1 ]]; then
_environment_variables_oauth2
_register_setup_function '_setup_oauth2'
fi
if [[ ${ENABLE_SASLAUTHD} -eq 1 ]]; then if [[ ${ENABLE_SASLAUTHD} -eq 1 ]]; then
_environment_variables_saslauthd _environment_variables_saslauthd
_register_setup_function '_setup_saslauthd' _register_setup_function '_setup_saslauthd'
@ -115,6 +120,11 @@ function _register_functions() {
_register_setup_function '_setup_apply_fixes_after_configuration' _register_setup_function '_setup_apply_fixes_after_configuration'
_register_setup_function '_environment_variables_export' _register_setup_function '_environment_variables_export'
if [[ ${ENABLE_MTA_STS} -eq 1 ]]; then
_register_setup_function '_setup_mta_sts'
_register_start_daemon '_start_daemon_mta_sts_daemon'
fi
# ? >> Daemons # ? >> Daemons
_register_start_daemon '_start_daemon_cron' _register_start_daemon '_start_daemon_cron'

View File

@ -38,6 +38,7 @@ function _start_daemon_opendkim { _default_start_daemon 'opendkim' ;
function _start_daemon_opendmarc { _default_start_daemon 'opendmarc' ; } function _start_daemon_opendmarc { _default_start_daemon 'opendmarc' ; }
function _start_daemon_postgrey { _default_start_daemon 'postgrey' ; } function _start_daemon_postgrey { _default_start_daemon 'postgrey' ; }
function _start_daemon_postsrsd { _default_start_daemon 'postsrsd' ; } function _start_daemon_postsrsd { _default_start_daemon 'postsrsd' ; }
function _start_daemon_mta_sts_daemon { _default_start_daemon 'mta-sts-daemon' ; }
function _start_daemon_rspamd { _default_start_daemon 'rspamd' ; } function _start_daemon_rspamd { _default_start_daemon 'rspamd' ; }
function _start_daemon_rspamd_redis { _default_start_daemon 'rspamd-redis' ; } function _start_daemon_rspamd_redis { _default_start_daemon 'rspamd-redis' ; }
function _start_daemon_rsyslog { _default_start_daemon 'rsyslog' ; } function _start_daemon_rsyslog { _default_start_daemon 'rsyslog' ; }

View File

@ -24,6 +24,7 @@ function _setup_save_states() {
[[ ${ENABLE_FAIL2BAN} -eq 1 ]] && SERVICEDIRS+=('lib/fail2ban') [[ ${ENABLE_FAIL2BAN} -eq 1 ]] && SERVICEDIRS+=('lib/fail2ban')
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/fetchmail') [[ ${ENABLE_FETCHMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/fetchmail')
[[ ${ENABLE_GETMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/getmail') [[ ${ENABLE_GETMAIL} -eq 1 ]] && SERVICEDIRS+=('lib/getmail')
[[ ${ENABLE_MTA_STS} -eq 1 ]] && SERVICEDIRS+=('lib/mta-sts')
[[ ${ENABLE_POSTGREY} -eq 1 ]] && SERVICEDIRS+=('lib/postgrey') [[ ${ENABLE_POSTGREY} -eq 1 ]] && SERVICEDIRS+=('lib/postgrey')
[[ ${ENABLE_RSPAMD} -eq 1 ]] && SERVICEDIRS+=('lib/rspamd') [[ ${ENABLE_RSPAMD} -eq 1 ]] && SERVICEDIRS+=('lib/rspamd')
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && SERVICEDIRS+=('lib/redis') [[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && SERVICEDIRS+=('lib/redis')
@ -84,6 +85,7 @@ function _setup_save_states() {
[[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis "${STATEDIR}/lib-amavis" [[ ${ENABLE_AMAVIS} -eq 1 ]] && chown -R amavis:amavis "${STATEDIR}/lib-amavis"
[[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav "${STATEDIR}/lib-clamav" [[ ${ENABLE_CLAMAV} -eq 1 ]] && chown -R clamav:clamav "${STATEDIR}/lib-clamav"
[[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup "${STATEDIR}/lib-fetchmail" [[ ${ENABLE_FETCHMAIL} -eq 1 ]] && chown -R fetchmail:nogroup "${STATEDIR}/lib-fetchmail"
[[ ${ENABLE_MTA_STS} -eq 1 ]] && chown -R _mta-sts:_mta-sts "${STATEDIR}/lib-mta-sts"
[[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey "${STATEDIR}/lib-postgrey" [[ ${ENABLE_POSTGREY} -eq 1 ]] && chown -R postgrey:postgrey "${STATEDIR}/lib-postgrey"
[[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd "${STATEDIR}/lib-rspamd" [[ ${ENABLE_RSPAMD} -eq 1 ]] && chown -R _rspamd:_rspamd "${STATEDIR}/lib-rspamd"
[[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && chown -R redis:redis "${STATEDIR}/lib-redis" [[ ${ENABLE_RSPAMD_REDIS} -eq 1 ]] && chown -R redis:redis "${STATEDIR}/lib-redis"

View File

@ -0,0 +1,7 @@
#!/bin/bash
function _setup_mta_sts() {
_log 'trace' 'Adding MTA-STS lookup to the Postfix TLS policy map'
_add_to_or_update_postfix_main smtp_tls_policy_maps 'socketmap:unix:/var/run/mta-sts/daemon.sock:postfix'
}

View File

@ -0,0 +1,11 @@
#!/bin/bash
function _setup_oauth2() {
_log 'debug' 'Setting up OAUTH2'
# Enable OAuth2 PassDB (Authentication):
sedfile -i -e '/\!include auth-oauth2\.conf\.ext/s/^#//' /etc/dovecot/conf.d/10-auth.conf
_replace_by_env_in_file 'OAUTH2_' '/etc/dovecot/dovecot-oauth2.conf.ext'
return 0
}

View File

@ -83,6 +83,7 @@ function __environment_variables_general_setup() {
VARS[ENABLE_FETCHMAIL]="${ENABLE_FETCHMAIL:=0}" VARS[ENABLE_FETCHMAIL]="${ENABLE_FETCHMAIL:=0}"
VARS[ENABLE_GETMAIL]="${ENABLE_GETMAIL:=0}" VARS[ENABLE_GETMAIL]="${ENABLE_GETMAIL:=0}"
VARS[ENABLE_MANAGESIEVE]="${ENABLE_MANAGESIEVE:=0}" VARS[ENABLE_MANAGESIEVE]="${ENABLE_MANAGESIEVE:=0}"
VARS[ENABLE_OAUTH2]="${ENABLE_OAUTH2:=0}"
VARS[ENABLE_OPENDKIM]="${ENABLE_OPENDKIM:=1}" VARS[ENABLE_OPENDKIM]="${ENABLE_OPENDKIM:=1}"
VARS[ENABLE_OPENDMARC]="${ENABLE_OPENDMARC:=1}" VARS[ENABLE_OPENDMARC]="${ENABLE_OPENDMARC:=1}"
VARS[ENABLE_POLICYD_SPF]="${ENABLE_POLICYD_SPF:=1}" VARS[ENABLE_POLICYD_SPF]="${ENABLE_POLICYD_SPF:=1}"
@ -151,6 +152,12 @@ function __environment_variables_general_setup() {
VARS[UPDATE_CHECK_INTERVAL]="${UPDATE_CHECK_INTERVAL:=1d}" VARS[UPDATE_CHECK_INTERVAL]="${UPDATE_CHECK_INTERVAL:=1d}"
} }
function _environment_variables_oauth2() {
_log 'debug' 'Setting OAUTH2-related environment variables now'
VARS[OAUTH2_INTROSPECTION_URL]="${OAUTH2_INTROSPECTION_URL:=}"
}
# This function handles environment variables related to LDAP. # This function handles environment variables related to LDAP.
# NOTE: SASLAuthd and Dovecot LDAP support inherit these common ENV. # NOTE: SASLAuthd and Dovecot LDAP support inherit these common ENV.
function _environment_variables_ldap() { function _environment_variables_ldap() {

View File

@ -157,3 +157,15 @@ autostart=false
stdout_logfile=/var/log/supervisor/%(program_name)s.log stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log stderr_logfile=/var/log/supervisor/%(program_name)s.log
command=/bin/bash -l -c /usr/local/bin/update-check.sh command=/bin/bash -l -c /usr/local/bin/update-check.sh
# Docs: https://github.com/Snawoot/postfix-mta-sts-resolver/blob/master/man/mta-sts-daemon.1.adoc
[program:mta-sts-daemon]
startsecs=0
stopwaitsecs=55
autostart=false
autorestart=true
stdout_logfile=/var/log/supervisor/%(program_name)s.log
stderr_logfile=/var/log/supervisor/%(program_name)s.log
command=/usr/bin/mta-sts-daemon --config /etc/mta-sts-daemon.yml
user=_mta-sts
environment=HOME=/var/lib/mta-sts

View File

@ -0,0 +1,56 @@
# OAuth2 mock service
#
# Dovecot will query this service with the token it was provided.
# If the session for the token is valid, a response provides an attribute to perform a UserDB lookup on (default: email).
import json
import base64
from http.server import BaseHTTPRequestHandler, HTTPServer
# OAuth2.0 Bearer token (paste into https://jwt.io/ to check it's contents).
# You should never need to edit this unless you REALLY need to change the issuer.
token = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwOi8vcHJvdmlkZXIuZXhhbXBsZS50ZXN0OjgwMDAvIiwic3ViIjoiODJjMWMzMzRkY2M2ZTMxMWFlNGFhZWJmZTk0NmM1ZTg1OGYwNTVhZmYxY2U1YTM3YWE3Y2M5MWFhYjE3ZTM1YyIsImF1ZCI6Im1haWxzZXJ2ZXIiLCJ1aWQiOiI4OU4zR0NuN1M1Y090WkZNRTVBeVhNbmxURFdVcnEzRmd4YWlyWWhFIn0.zuCytArbphhJn9XT_y9cBdGqDCNo68tBrtOwPIsuKNyF340SaOuZa0xarZofygytdDpLtYr56QlPTKImi-n1ZWrHkRZkwrQi5jQ-j_n2hEAL0vUToLbDnXYfc5q2w7z7X0aoCmiK8-fV7Kx4CVTM7riBgpElf6F3wNAIcX6R1ijUh6ISCL0XYsdogf8WUNZipXY-O4R7YHXdOENuOp3G48hWhxuUh9PsUqE5yxDwLsOVzCTqg9S5gxPQzF2eCN9J0I2XiIlLKvLQPIZ2Y_K7iYvVwjpNdgb4xhm9wuKoIVinYkF_6CwIzAawBWIDJAbix1IslkUPQMGbupTDtOgTiQ"
# This is the string the user-facing client (e.g. Roundcube) should send via IMAP to Dovecot.
# We include the user and the above token separated by '\1' chars as per the XOAUTH2 spec.
xoauth2 = base64.b64encode(f"user=user1@localhost.localdomain\1auth=Bearer {token}\1\1".encode("utf-8"))
# If changing the user above, use the new output from the below line with the contents of the AUTHENTICATE command in test/test-files/auth/imap-oauth2-auth.txt
print("XOAUTH2 string: " + str(xoauth2))
class HTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
auth = self.headers.get("Authorization")
if auth is None:
self.send_response(401)
self.end_headers()
return
if len(auth.split()) != 2:
self.send_response(401)
self.end_headers()
return
auth = auth.split()[1]
# Valid session, respond with JSON containing the expected `email` claim to match as Dovecot username:
if auth == token:
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({
"email": "user1@localhost.localdomain",
"email_verified": True,
"sub": "82c1c334dcc6e311ae4aaebfe946c5e858f055aff1ce5a37aa7cc91aab17e35c"
}).encode("utf-8"))
else:
self.send_response(401)
self.end_headers()
server = HTTPServer(('', 80), HTTPRequestHandler)
print("Starting server", flush=True)
try:
server.serve_forever()
except KeyboardInterrupt:
print()
print("Received keyboard interrupt")
finally:
print("Exiting")

View File

@ -0,0 +1,4 @@
a0 NOOP See test/config/oauth2/provider.py to generate the below XOAUTH2 string
a1 AUTHENTICATE XOAUTH2 dXNlcj11c2VyMUBsb2NhbGhvc3QubG9jYWxkb21haW4BYXV0aD1CZWFyZXIgZXlKaGJHY2lPaUpTVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SnBjM01pT2lKb2RIUndPaTh2Y0hKdmRtbGtaWEl1WlhoaGJYQnNaUzUwWlhOME9qZ3dNREF2SWl3aWMzVmlJam9pT0RKak1XTXpNelJrWTJNMlpUTXhNV0ZsTkdGaFpXSm1aVGswTm1NMVpUZzFPR1l3TlRWaFptWXhZMlUxWVRNM1lXRTNZMk01TVdGaFlqRTNaVE0xWXlJc0ltRjFaQ0k2SW0xaGFXeHpaWEoyWlhJaUxDSjFhV1FpT2lJNE9VNHpSME51TjFNMVkwOTBXa1pOUlRWQmVWaE5ibXhVUkZkVmNuRXpSbWQ0WVdseVdXaEZJbjAuenVDeXRBcmJwaGhKbjlYVF95OWNCZEdxRENObzY4dEJydE93UElzdUtOeUYzNDBTYU91WmEweGFyWm9meWd5dGREcEx0WXI1NlFsUFRLSW1pLW4xWldySGtSWmt3clFpNWpRLWpfbjJoRUFMMHZVVG9MYkRuWFlmYzVxMnc3ejdYMGFvQ21pSzgtZlY3S3g0Q1ZUTTdyaUJncEVsZjZGM3dOQUljWDZSMWlqVWg2SVNDTDBYWXNkb2dmOFdVTlppcFhZLU80UjdZSFhkT0VOdU9wM0c0OGhXaHh1VWg5UHNVcUU1eXhEd0xzT1Z6Q1RxZzlTNWd4UFF6RjJlQ045SjBJMlhpSWxMS3ZMUVBJWjJZX0s3aVl2VndqcE5kZ2I0eGhtOXd1S29JVmluWWtGXzZDd0l6QWF3QldJREpBYml4MUlzbGtVUFFNR2J1cFREdE9nVGlRAQE=
a2 EXAMINE INBOX
a3 LOGOUT

View File

@ -1,6 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message amavis/spam.txt
This is a test mail.
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <added@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-added.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <alias1@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-alias-external.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local Alias <alias2@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-alias-local.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local Alias With Delimiter <alias1+test@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-alias-recipient-delimiter.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <wildcard@localdomain2.com>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-catchall-local.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <bounce-always@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-regexp-alias-external.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <test123@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-regexp-alias-local.txt
This is a test mail.

View File

@ -1,6 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <user1@localhost.localdomain>
Cc: Existing Local Alias <alias2@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-user-and-cc-local-alias.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message existing-user1.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <dockermailserver@external.tld>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message non-existing-user.txt
This is a test mail.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <pass@example.test>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 22 May 2010 07:43:25 -0400
Subject: Test Message rspamd/pass.txt
This mail should pass and Rspamd should not mark it.

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <spam-header@example.test>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 21 Jan 2023 11:11:11 +0000
Subject: Test Message rspamd-spam-header.txt
YJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <spam@example.test>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 21 Jan 2023 11:11:11 +0000
Subject: Test Message rspamd-spam.txt
XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X

View File

@ -1,5 +0,0 @@
From: Docker Mail Server <virus@example.test>
To: Existing Local User <user1@localhost.localdomain>
Date: Sat, 21 Jan 2023 11:11:11 +0000
Subject: Test Message rspamd-virus.txt
X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*

View File

@ -466,7 +466,7 @@ function _print_mail_log_for_id() {
local MAIL_ID=${1:?Mail ID must be provided} local MAIL_ID=${1:?Mail ID must be provided}
local CONTAINER_NAME=$(__handle_container_name "${2:-}") local CONTAINER_NAME=$(__handle_container_name "${2:-}")
_run_in_container grep -F "${MAIL_ID}" /var/log/mail.log _run_in_container grep -E "${MAIL_ID}" /var/log/mail.log
} }
# A simple wrapper for netcat (`nc`). This is useful when sending # A simple wrapper for netcat (`nc`). This is useful when sending
@ -480,7 +480,7 @@ function _nc_wrapper() {
[[ -v CONTAINER_NAME ]] || return 1 [[ -v CONTAINER_NAME ]] || return 1
_run_in_container_bash "nc ${NC_PARAMETERS} < /tmp/docker-mailserver-test/${FILE}.txt" _run_in_container_bash "nc ${NC_PARAMETERS} < /tmp/docker-mailserver-test/${FILE}"
} }
# ? << Miscellaneous helper functions # ? << Miscellaneous helper functions

View File

@ -7,68 +7,118 @@
# ! ATTENTION: This file is loaded by `common.sh` - do not load it yourself! # ! ATTENTION: This file is loaded by `common.sh` - do not load it yourself!
# ! ATTENTION: This file requires helper functions from `common.sh`! # ! ATTENTION: This file requires helper functions from `common.sh`!
# Sends a mail from localhost (127.0.0.1) to a container. To send # Sends an e-mail from the container named by the environment variable `CONTAINER_NAME`
# a custom email, create a file at `test/files/<TEST FILE>`, # to the same or another container.
# and provide `<TEST FILE>` as an argument to this function.
# #
# Parameters include all options that one can supply to `swaks` # To send a custom email, you can
# itself. The `--data` parameter expects a relative path from `emails/` #
# where the contents will be implicitly provided to `swaks` via STDIN. # 1. create a file at `test/files/<TEST FILE>` and provide `<TEST FILE>` via `--data` as an argument to this function;
# 2. use this function without the `--data` argument, in which case we provide a default;
# 3. provide data inline (`--data <INLINE DATA>`).
#
# The very first parameter **may** be `--expect-rejection` - use it of you expect the mail transaction to not finish
# successfully. All other (following) parameters include all options that one can supply to `swaks` itself.
# As mentioned before, the `--data` parameter expects a value of either:
#
# - A relative path from `test/files/emails/`
# - An "inline" data string (e.g., `Date: 1 Jan 2024\nSubject: This is a test`)
#
# ## Output
#
# This functions prints the output of the transaction that `swaks` prints.
# #
# ## Attention # ## Attention
# #
# This function assumes `CONTAINER_NAME` to be properly set (to the container # This function assumes `CONTAINER_NAME` to be properly set (to the container
# name the command should be executed in)! # name the command should be executed in)!
# #
# This function will just send the email in an "asynchronous" fashion, i.e. it will # This function will send the email in an "asynchronous" fashion,
# send the email but it will not make sure the mail queue is empty after the mail # it will return without waiting for the Postfix mail queue to be emptied.
# has been sent.
function _send_email() { function _send_email() {
[[ -v CONTAINER_NAME ]] || return 1 local RETURN_VALUE=0
local COMMAND_STRING
# Parameter defaults common to our testing needs: function __parse_arguments() {
local EHLO='mail.external.tld' [[ -v CONTAINER_NAME ]] || return 1
local FROM='user@external.tld'
local TO='user1@localhost.localdomain'
local SERVER='0.0.0.0'
local PORT=25
# Extra options for `swaks` that aren't covered by the default options above:
local ADDITIONAL_SWAKS_OPTIONS=()
# Specifically for handling `--data` option below:
local FINAL_SWAKS_OPTIONS=()
while [[ ${#} -gt 0 ]]; do # Parameter defaults common to our testing needs:
case "${1}" in local EHLO='mail.external.tld'
( '--ehlo' ) EHLO=${2:?--ehlo given but no argument} ; shift 2 ;; local FROM='user@external.tld'
( '--from' ) FROM=${2:?--from given but no argument} ; shift 2 ;; local TO='user1@localhost.localdomain'
( '--to' ) TO=${2:?--to given but no argument} ; shift 2 ;; local SERVER='0.0.0.0'
( '--server' ) SERVER=${2:?--server given but no argument} ; shift 2 ;; local PORT=25
( '--port' ) PORT=${2:?--port given but no argument} ; shift 2 ;; # Extra options for `swaks` that aren't covered by the default options above:
( '--data' ) local ADDITIONAL_SWAKS_OPTIONS=()
local TEMPLATE_FILE="/tmp/docker-mailserver-test/emails/${2:?--data given but no argument provided}.txt" local DATA_WAS_SUPPLIED=0
FINAL_SWAKS_OPTIONS+=('--data')
FINAL_SWAKS_OPTIONS+=('-')
FINAL_SWAKS_OPTIONS+=('<')
FINAL_SWAKS_OPTIONS+=("${TEMPLATE_FILE}")
shift 2
;;
( * ) ADDITIONAL_SWAKS_OPTIONS+=("${1}") ; shift 1 ;;
esac
done
_run_in_container_bash "swaks --server ${SERVER} --port ${PORT} --ehlo ${EHLO} --from ${FROM} --to ${TO} ${ADDITIONAL_SWAKS_OPTIONS[*]} ${FINAL_SWAKS_OPTIONS[*]}" while [[ ${#} -gt 0 ]]; do
case "${1}" in
( '--ehlo' ) EHLO=${2:?--ehlo given but no argument} ; shift 2 ;;
( '--from' ) FROM=${2:?--from given but no argument} ; shift 2 ;;
( '--to' ) TO=${2:?--to given but no argument} ; shift 2 ;;
( '--server' ) SERVER=${2:?--server given but no argument} ; shift 2 ;;
( '--port' ) PORT=${2:?--port given but no argument} ; shift 2 ;;
( '--data' )
ADDITIONAL_SWAKS_OPTIONS+=('--data')
local FILE_PATH="/tmp/docker-mailserver-test/emails/${2:?--data given but no argument provided}"
if _exec_in_container_bash "[[ -e ${FILE_PATH} ]]"; then
ADDITIONAL_SWAKS_OPTIONS+=("@${FILE_PATH}")
else
ADDITIONAL_SWAKS_OPTIONS+=("'${2}'")
fi
shift 2
DATA_WAS_SUPPLIED=1
;;
( * ) ADDITIONAL_SWAKS_OPTIONS+=("'${1}'") ; shift 1 ;;
esac
done
if [[ ${DATA_WAS_SUPPLIED} -eq 0 ]]; then
# Fallback template (without the implicit `Message-Id` + `X-Mailer` headers from swaks):
# NOTE: It is better to let Postfix generate and append the `Message-Id` header itself,
# as it will contain the Queue ID for tracking in logs (which is also returned in swaks output).
ADDITIONAL_SWAKS_OPTIONS+=('--data')
ADDITIONAL_SWAKS_OPTIONS+=("'Date: %DATE%\nTo: %TO_ADDRESS%\nFrom: %FROM_ADDRESS%\nSubject: test %DATE%\n%NEW_HEADERS%\n%BODY%\n'")
fi
echo "swaks --server '${SERVER}' --port '${PORT}' --ehlo '${EHLO}' --from '${FROM}' --to '${TO}' ${ADDITIONAL_SWAKS_OPTIONS[*]}"
}
if [[ ${1:-} == --expect-rejection ]]; then
shift 1
COMMAND_STRING=$(__parse_arguments "${@}")
_run_in_container_bash "${COMMAND_STRING}"
RETURN_VALUE=${?}
else
COMMAND_STRING=$(__parse_arguments "${@}")
_run_in_container_bash "${COMMAND_STRING}"
assert_success
fi
# shellcheck disable=SC2154
echo "${output}"
return "${RETURN_VALUE}"
} }
# Like `_send_email` with two major differences: # Like `_send_email` with two major differences:
# #
# 1. this function waits for the mail to be processed; there is no asynchronicity # 1. this function waits for the mail to be processed; there is no asynchronicity
# because filtering the logs in a synchronous way is easier and safer! # because filtering the logs in a synchronous way is easier and safer;
# 2. this function prints an ID one can later filter by to check logs # 2. this function takes the name of a variable and inserts IDs one can later
# filter by to check logs.
# #
# No. 2 is especially useful in case you send more than one email in a single # No. 2 is especially useful in case you send more than one email in a single
# test file and need to assert certain log entries for each mail individually. # test file and need to assert certain log entries for each mail individually.
# #
# This function takes the same arguments as `_send_mail`. # The first argument has to be the name of the variable that the e-mail ID is stored in.
# The second argument **can** be the flag `--expect-rejection`.
#
# - If this flag is supplied, the function does not check whether the whole mail delivery
# transaction was successful. Additionally the queue ID will be retrieved differently.
# - CAUTION: It must still be possible to `grep` for the Message-ID that Postfix
# generated in the mail log; otherwise this function fails.
#
# The rest of the arguments are the same as `_send_email`.
# #
# ## Attention # ## Attention
# #
@ -82,20 +132,42 @@ function _send_email() {
# chosen. Sending more than one mail at any given point in time with this function # chosen. Sending more than one mail at any given point in time with this function
# is UNDEFINED BEHAVIOR! # is UNDEFINED BEHAVIOR!
function _send_email_and_get_id() { function _send_email_and_get_id() {
[[ -v CONTAINER_NAME ]] || return 1 # Export the variable denoted by ${1} so everyone has access
export "${1:?Mail ID must be set for _send_email_and_get_id}"
# Get a "reference" to the content of the variable denoted by ${1} so we can manipulate the content
local -n ID_ENV_VAR_REF=${1:?}
# Prepare the message ID header here because we will shift away ${1} later
local MID="<${1}@dms-tests>"
# Get rid of ${1} so only the arguments for swaks remain
shift 1
_wait_for_empty_mail_queue_in_container
_send_email "${@}"
_wait_for_empty_mail_queue_in_container
local MAIL_ID
# The unique ID Postfix (and other services) use may be different in length # The unique ID Postfix (and other services) use may be different in length
# on different systems (e.g. amd64 (11) vs aarch64 (10)). Hence, we use a # on different systems. Hence, we use a range to safely capture it.
# range to safely capture it. local QUEUE_ID_REGEX='[A-Z0-9]{9,12}'
MAIL_ID=$(_exec_in_container tac /var/log/mail.log \
| grep -E -m 1 'postfix/smtpd.*: [A-Z0-9]+: client=localhost' \
| grep -E -o '[A-Z0-9]{9,12}' || true)
assert_not_equal "${MAIL_ID}" '' _wait_for_empty_mail_queue_in_container
echo "${MAIL_ID}" _send_email "${@}" --header "Message-Id: ${MID}"
_wait_for_empty_mail_queue_in_container
# We store Postfix's queue ID first
ID_ENV_VAR_REF=$(_exec_in_container tac /var/log/mail.log \
| grep -E "postfix/cleanup.*: ${QUEUE_ID_REGEX}:.*message-id=${MID}" \
| grep -E --only-matching --max-count 1 "${QUEUE_ID_REGEX}" || :)
# But we also requre potential Dovecot sieve output, which requires the mesage ID,
# so we need to provide the message ID too.
ID_ENV_VAR_REF+="|${MID}"
# Last but not least, we perform plausibility checks on the IDs.
assert_not_equal "${ID_ENV_VAR_REF}" ''
run echo "${ID_ENV_VAR_REF}"
assert_line --regexp "^${QUEUE_ID_REGEX}\|${MID}$"
}
# Send a spam e-mail by utilizing GTUBE.
#
# Extra arguments given to this function will be supplied by `_send_email_and_get_id` directly.
function _send_spam() {
_send_email_and_get_id MAIL_ID_SPAM "${@}" \
--from 'spam@external.tld' \
--body 'XJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X'
} }

View File

@ -225,12 +225,9 @@ function teardown_file() { _default_teardown ; }
sleep 10 sleep 10
# send some big emails # send some big emails
_send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded' _send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded.txt'
assert_success _send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded.txt'
_send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded' _send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded.txt'
assert_success
_send_email --to 'quotauser@otherdomain.tld' --data 'quota-exceeded'
assert_success
# check for quota warn message existence # check for quota warn message existence
run _repeat_until_success_or_timeout 20 _exec_in_container grep -R 'Subject: quota warning' /var/mail/otherdomain.tld/quotauser/new/ run _repeat_until_success_or_timeout 20 _exec_in_container grep -R 'Subject: quota warning' /var/mail/otherdomain.tld/quotauser/new/
assert_success assert_success

View File

@ -26,11 +26,9 @@ function setup_file() {
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
# Single mail sent from 'spam@spam.com' that is handled by User (relocate) and Global (copy) sieves for user1: # Single mail sent from 'spam@spam.com' that is handled by User (relocate) and Global (copy) sieves for user1:
_send_email --data 'sieve/spam-folder' _send_email --data 'sieve/spam-folder.txt'
assert_success
# Mail for user2 triggers the sieve-pipe: # Mail for user2 triggers the sieve-pipe:
_send_email --to 'user2@otherdomain.tld' --data 'sieve/pipe' _send_email --to 'user2@otherdomain.tld' --data 'sieve/pipe.txt'
assert_success
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
} }

View File

@ -26,8 +26,7 @@ function teardown() { _default_teardown ; }
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS' _common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_send_email --data 'existing/user1' _send_email
assert_success
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
# Mail received should be stored as `u.1` (one file per message) # Mail received should be stored as `u.1` (one file per message)
@ -48,8 +47,7 @@ function teardown() { _default_teardown ; }
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS' _common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_send_email --data 'existing/user1' _send_email
assert_success
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
# Mail received should be stored in `m.1` (1 or more messages) # Mail received should be stored in `m.1` (1 or more messages)

View File

@ -14,8 +14,7 @@ function setup_file() {
function teardown_file() { _default_teardown ; } function teardown_file() { _default_teardown ; }
@test 'normal delivery works' { @test 'normal delivery works' {
_send_email --data 'existing/user1' _send_email
assert_success
_count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new 1 _count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new 1
} }
@ -27,7 +26,7 @@ function teardown_file() { _default_teardown ; }
} }
@test "(IMAP) special-use folders should be created when necessary" { @test "(IMAP) special-use folders should be created when necessary" {
_nc_wrapper 'nc/imap_special_use_folders' '-w 8 0.0.0.0 143' _nc_wrapper 'nc/imap_special_use_folders.txt' '-w 8 0.0.0.0 143'
assert_output --partial 'Drafts' assert_output --partial 'Drafts'
assert_output --partial 'Junk' assert_output --partial 'Junk'
assert_output --partial 'Trash' assert_output --partial 'Trash'

View File

@ -25,8 +25,7 @@ function setup_file() {
_wait_for_service postfix _wait_for_service postfix
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_send_email --from 'virus@external.tld' --data 'amavis/virus' _send_email --from 'virus@external.tld' --data 'amavis/virus.txt'
assert_success
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
} }

View File

@ -18,8 +18,7 @@ function setup_file() {
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS' _common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_send_email --data 'existing/user1' _send_email
assert_success
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
} }

View File

@ -74,7 +74,7 @@ function teardown_file() {
CONTAINER1_IP=$(_get_container_ip "${CONTAINER1_NAME}") CONTAINER1_IP=$(_get_container_ip "${CONTAINER1_NAME}")
# Trigger a ban by failing to login twice: # Trigger a ban by failing to login twice:
for _ in {1..2}; do for _ in {1..2}; do
CONTAINER_NAME=${CONTAINER2_NAME} _send_email \ CONTAINER_NAME=${CONTAINER2_NAME} _send_email --expect-rejection \
--server "${CONTAINER1_IP}" \ --server "${CONTAINER1_IP}" \
--port 465 \ --port 465 \
--auth PLAIN \ --auth PLAIN \

View File

@ -51,7 +51,7 @@ function teardown_file() { _default_teardown ; }
_reload_postfix _reload_postfix
# Send test mail (it should fail to deliver): # Send test mail (it should fail to deliver):
_send_email --from 'user@external.tld' --port 25 --data 'postgrey' _send_email --expect-rejection --from 'user@external.tld' --port 25 --data 'postgrey.txt'
assert_failure assert_failure
assert_output --partial 'Recipient address rejected: Delayed by Postgrey' assert_output --partial 'Recipient address rejected: Delayed by Postgrey'
@ -67,8 +67,7 @@ function teardown_file() { _default_teardown ; }
# Wait until `$POSTGREY_DELAY` seconds pass before trying again: # Wait until `$POSTGREY_DELAY` seconds pass before trying again:
sleep 3 sleep 3
# Retry delivering test mail (it should be trusted this time): # Retry delivering test mail (it should be trusted this time):
_send_email --from 'user@external.tld' --port 25 --data 'postgrey' _send_email --from 'user@external.tld' --port 25 --data 'postgrey.txt'
assert_success
# Confirm postgrey permitted delivery (triplet is now trusted): # Confirm postgrey permitted delivery (triplet is now trusted):
_should_have_log_entry \ _should_have_log_entry \
@ -87,7 +86,7 @@ function teardown_file() { _default_teardown ; }
# - It'd also cause the earlier greylist test to fail. # - It'd also cause the earlier greylist test to fail.
# - TODO: Actually confirm whitelist feature works correctly as these test cases are using a workaround: # - TODO: Actually confirm whitelist feature works correctly as these test cases are using a workaround:
@test "should whitelist sender 'user@whitelist.tld'" { @test "should whitelist sender 'user@whitelist.tld'" {
_nc_wrapper 'nc/postgrey_whitelist' '-w 0 0.0.0.0 10023' _nc_wrapper 'nc/postgrey_whitelist.txt' '-w 0 0.0.0.0 10023'
_should_have_log_entry \ _should_have_log_entry \
'action=pass' \ 'action=pass' \
@ -96,7 +95,7 @@ function teardown_file() { _default_teardown ; }
} }
@test "should whitelist recipient 'user2@otherdomain.tld'" { @test "should whitelist recipient 'user2@otherdomain.tld'" {
_nc_wrapper 'nc/postgrey_whitelist_recipients' '-w 0 0.0.0.0 10023' _nc_wrapper 'nc/postgrey_whitelist_recipients.txt' '-w 0 0.0.0.0 10023'
_should_have_log_entry \ _should_have_log_entry \
'action=pass' \ 'action=pass' \

View File

@ -44,7 +44,7 @@ function teardown_file() {
# Use `nc` to send all SMTP commands at once instead (emulate a misbehaving client that should be rejected) # Use `nc` to send all SMTP commands at once instead (emulate a misbehaving client that should be rejected)
# NOTE: Postscreen only runs on port 25, avoid implicit ports in test methods # NOTE: Postscreen only runs on port 25, avoid implicit ports in test methods
@test 'should fail send when talking out of turn' { @test 'should fail send when talking out of turn' {
CONTAINER_NAME=${CONTAINER2_NAME} _nc_wrapper 'emails/nc_raw/postscreen' "${CONTAINER1_IP} 25" CONTAINER_NAME=${CONTAINER2_NAME} _nc_wrapper 'emails/nc_raw/postscreen.txt' "${CONTAINER1_IP} 25"
# Expected postscreen log entry: # Expected postscreen log entry:
assert_output --partial 'Protocol error' assert_output --partial 'Protocol error'
@ -56,14 +56,10 @@ function teardown_file() {
@test "should successfully pass postscreen and get postfix greeting message (respecting postscreen_greet_wait time)" { @test "should successfully pass postscreen and get postfix greeting message (respecting postscreen_greet_wait time)" {
# Configure `send_email()` to send from the mail client container (CONTAINER2_NAME) via ENV override, # Configure `send_email()` to send from the mail client container (CONTAINER2_NAME) via ENV override,
# mail is sent to the DMS server container (CONTAINER1_NAME) via `--server` parameter: # mail is sent to the DMS server container (CONTAINER1_NAME) via `--server` parameter:
CONTAINER_NAME=${CONTAINER2_NAME} _send_email --server "${CONTAINER1_IP}" --port 25 --data 'postscreen' # TODO: Use _send_email_and_get_id when proper resolution of domain names is possible:
# NOTE: Cannot assert_success due to sender address not being resolvable. CONTAINER_NAME=${CONTAINER2_NAME} _send_email --expect-rejection --server "${CONTAINER1_IP}" --port 25 --data 'postscreen.txt'
# TODO: Uncomment when proper resolution of domain names is possible: # CONTAINER_NAME=${CONTAINER2_NAME} _send_email_and_get_id MAIL_ID_POSTSCREEN --server "${CONTAINER1_IP}" --data 'postscreen.txt'
# assert_success # _print_mail_log_for_id "${MAIL_ID_POSTSCREEN}"
# TODO: Prefer this approach when `_send_email_and_get_id()` can support separate client and server containers:
# local MAIL_ID=$(_send_email_and_get_id --port 25 --data 'postscreen')
# _print_mail_log_for_id "${MAIL_ID}"
# assert_output --partial "stored mail into mailbox 'INBOX'" # assert_output --partial "stored mail into mailbox 'INBOX'"
_run_in_container cat /var/log/mail.log _run_in_container cat /var/log/mail.log

View File

@ -43,16 +43,22 @@ function setup_file() {
_wait_for_service postfix _wait_for_service postfix
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
# We will send 3 emails: the first one should pass just fine; the second one should # We will send 4 emails:
# be rejected due to spam; the third one should be rejected due to a virus. # 1. The first one should pass just fine
export MAIL_ID1=$(_send_email_and_get_id --from 'rspamd-pass@example.test' --data 'rspamd/pass') _send_email_and_get_id MAIL_ID_PASS
export MAIL_ID2=$(_send_email_and_get_id --from 'rspamd-spam@example.test' --data 'rspamd/spam') # 2. The second one should be rejected (Rspamd-specific GTUBE pattern for rejection)
export MAIL_ID3=$(_send_email_and_get_id --from 'rspamd-virus@example.test' --data 'rspamd/virus') _send_spam --expect-rejection
export MAIL_ID4=$(_send_email_and_get_id --from 'rspamd-spam-header@example.test' --data 'rspamd/spam-header') # 3. The third one should be rejected due to a virus (ClamAV EICAR pattern)
# shellcheck disable=SC2016
_send_email_and_get_id MAIL_ID_VIRUS --expect-rejection \
--body 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*'
# 4. The fourth one will receive an added header (Rspamd-specific GTUBE pattern for adding a spam header)
# ref: https://rspamd.com/doc/gtube_patterns.html
_send_email_and_get_id MAIL_ID_HEADER --body "YJS*C4JDBQADN1.NSBN3*2IDNEN*GTUBE-STANDARD-ANTI-UBE-TEST-EMAIL*C.34X"
for ID in MAIL_ID{1,2,3,4}; do _run_in_container cat /var/log/mail.log
[[ -n ${!ID} ]] || { echo "${ID} is empty - aborting!" ; return 1 ; } assert_success
done refute_output --partial 'inet:localhost:11332: Connection refused'
} }
function teardown_file() { _default_teardown ; } function teardown_file() { _default_teardown ; }
@ -104,7 +110,7 @@ function teardown_file() { _default_teardown ; }
@test 'normal mail passes fine' { @test 'normal mail passes fine' {
_service_log_should_contain_string 'rspamd' 'F \(no action\)' _service_log_should_contain_string 'rspamd' 'F \(no action\)'
_print_mail_log_for_id "${MAIL_ID1}" _print_mail_log_for_id "${MAIL_ID_PASS}"
assert_output --partial "stored mail into mailbox 'INBOX'" assert_output --partial "stored mail into mailbox 'INBOX'"
_count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new/ 1 _count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new/ 1
@ -114,7 +120,7 @@ function teardown_file() { _default_teardown ; }
_service_log_should_contain_string 'rspamd' 'S \(reject\)' _service_log_should_contain_string 'rspamd' 'S \(reject\)'
_service_log_should_contain_string 'rspamd' 'reject "Gtube pattern"' _service_log_should_contain_string 'rspamd' 'reject "Gtube pattern"'
_print_mail_log_for_id "${MAIL_ID2}" _print_mail_log_for_id "${MAIL_ID_SPAM}"
assert_output --partial 'milter-reject' assert_output --partial 'milter-reject'
assert_output --partial '5.7.1 Gtube pattern' assert_output --partial '5.7.1 Gtube pattern'
@ -125,7 +131,7 @@ function teardown_file() { _default_teardown ; }
_service_log_should_contain_string 'rspamd' 'T \(reject\)' _service_log_should_contain_string 'rspamd' 'T \(reject\)'
_service_log_should_contain_string 'rspamd' 'reject "ClamAV FOUND VIRUS "Eicar-Signature"' _service_log_should_contain_string 'rspamd' 'reject "ClamAV FOUND VIRUS "Eicar-Signature"'
_print_mail_log_for_id "${MAIL_ID3}" _print_mail_log_for_id "${MAIL_ID_VIRUS}"
assert_output --partial 'milter-reject' assert_output --partial 'milter-reject'
assert_output --partial '5.7.1 ClamAV FOUND VIRUS "Eicar-Signature"' assert_output --partial '5.7.1 ClamAV FOUND VIRUS "Eicar-Signature"'
refute_output --partial "stored mail into mailbox 'INBOX'" refute_output --partial "stored mail into mailbox 'INBOX'"
@ -214,7 +220,7 @@ function teardown_file() { _default_teardown ; }
_service_log_should_contain_string 'rspamd' 'S \(add header\)' _service_log_should_contain_string 'rspamd' 'S \(add header\)'
_service_log_should_contain_string 'rspamd' 'add header "Gtube pattern"' _service_log_should_contain_string 'rspamd' 'add header "Gtube pattern"'
_print_mail_log_for_id "${MAIL_ID4}" _print_mail_log_for_id "${MAIL_ID_HEADER}"
assert_output --partial "fileinto action: stored mail into mailbox 'Junk'" assert_output --partial "fileinto action: stored mail into mailbox 'Junk'"
_count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new/ 1 _count_files_in_directory_in_container /var/mail/localhost.localdomain/user1/new/ 1
@ -256,7 +262,7 @@ function teardown_file() { _default_teardown ; }
# Move an email to the "Junk" folder from "INBOX"; the first email we # Move an email to the "Junk" folder from "INBOX"; the first email we
# sent should pass fine, hence we can now move it. # sent should pass fine, hence we can now move it.
_nc_wrapper 'nc/rspamd_imap_move_to_junk' '0.0.0.0 143' _nc_wrapper 'nc/rspamd_imap_move_to_junk.txt' '0.0.0.0 143'
sleep 1 # wait for the transaction to finish sleep 1 # wait for the transaction to finish
_run_in_container cat /var/log/mail/mail.log _run_in_container cat /var/log/mail/mail.log
@ -270,7 +276,7 @@ function teardown_file() { _default_teardown ; }
# Move an email to the "INBOX" folder from "Junk"; there should be two mails # Move an email to the "INBOX" folder from "Junk"; there should be two mails
# in the "Junk" folder, since the second email we sent during setup should # in the "Junk" folder, since the second email we sent during setup should
# have landed in the Junk folder already. # have landed in the Junk folder already.
_nc_wrapper 'nc/rspamd_imap_move_to_inbox' '0.0.0.0 143' _nc_wrapper 'nc/rspamd_imap_move_to_inbox.txt' '0.0.0.0 143'
sleep 1 # wait for the transaction to finish sleep 1 # wait for the transaction to finish
_run_in_container cat /var/log/mail/mail.log _run_in_container cat /var/log/mail/mail.log

View File

@ -95,7 +95,7 @@ function teardown() { _default_teardown ; }
function _should_send_spam_message() { function _should_send_spam_message() {
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_wait_for_tcp_port_in_container 10024 # port 10024 is for Amavis _wait_for_tcp_port_in_container 10024 # port 10024 is for Amavis
_send_email --from 'spam@external.tld' --data 'amavis/spam' _send_spam
} }
function _should_be_received_by_amavis() { function _should_be_received_by_amavis() {

View File

@ -207,7 +207,7 @@ function _should_have_correct_mail_headers() {
# (eg: OVERRIDE_HOSTNAME or `--hostname mail --domainname example.test`) # (eg: OVERRIDE_HOSTNAME or `--hostname mail --domainname example.test`)
local EXPECTED_HOSTNAME=${3:-${EXPECTED_FQDN}} local EXPECTED_HOSTNAME=${3:-${EXPECTED_FQDN}}
_send_email --from 'user@external.tld' --data 'existing/user1' _send_email --from 'user@external.tld'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
_count_files_in_directory_in_container '/var/mail/localhost.localdomain/user1/new/' '1' _count_files_in_directory_in_container '/var/mail/localhost.localdomain/user1/new/' '1'

View File

@ -21,6 +21,7 @@ function teardown() { _default_teardown ; }
# dovecot (/usr/sbin/dovecot) # dovecot (/usr/sbin/dovecot)
# fetchmail (/usr/bin/fetchmail) # fetchmail (/usr/bin/fetchmail)
# fail2ban-server (/usr/bin/python3 /usr/bin/fail2ban-server) - Started by fail2ban-wrapper.sh # fail2ban-server (/usr/bin/python3 /usr/bin/fail2ban-server) - Started by fail2ban-wrapper.sh
# mta-sts-daemon (/usr/bin/bin/python3 /usr/bin/mta-sts-daemon)
# postgrey (postgrey) - NOTE: This process lacks path information to match with `--full` in pgrep / pkill # postgrey (postgrey) - NOTE: This process lacks path information to match with `--full` in pgrep / pkill
# postsrsd (/usr/sbin/postsrsd) - NOTE: Also matches the wrapper: `/bin/bash /usr/local/bin/postsrsd-wrapper.sh` # postsrsd (/usr/sbin/postsrsd) - NOTE: Also matches the wrapper: `/bin/bash /usr/local/bin/postsrsd-wrapper.sh`
# saslauthd (/usr/sbin/saslauthd) - x5 of the same process are found running (1 is a parent of 4) # saslauthd (/usr/sbin/saslauthd) - x5 of the same process are found running (1 is a parent of 4)
@ -44,6 +45,7 @@ ENV_PROCESS_LIST=(
dovecot dovecot
fail2ban-server fail2ban-server
fetchmail fetchmail
mta-sts-daemon
opendkim opendkim
opendmarc opendmarc
postgrey postgrey
@ -58,6 +60,7 @@ ENV_PROCESS_LIST=(
--env ENABLE_CLAMAV=0 --env ENABLE_CLAMAV=0
--env ENABLE_FAIL2BAN=0 --env ENABLE_FAIL2BAN=0
--env ENABLE_FETCHMAIL=0 --env ENABLE_FETCHMAIL=0
--env ENABLE_MTA_STS=0
--env ENABLE_OPENDKIM=0 --env ENABLE_OPENDKIM=0
--env ENABLE_OPENDMARC=0 --env ENABLE_OPENDMARC=0
--env ENABLE_POSTGREY=0 --env ENABLE_POSTGREY=0
@ -93,6 +96,7 @@ ENV_PROCESS_LIST=(
--env ENABLE_AMAVIS=1 --env ENABLE_AMAVIS=1
--env ENABLE_FAIL2BAN=1 --env ENABLE_FAIL2BAN=1
--env ENABLE_FETCHMAIL=1 --env ENABLE_FETCHMAIL=1
--env ENABLE_MTA_STS=1
--env ENABLE_OPENDKIM=1 --env ENABLE_OPENDKIM=1
--env ENABLE_OPENDMARC=1 --env ENABLE_OPENDMARC=1
--env FETCHMAIL_PARALLEL=1 --env FETCHMAIL_PARALLEL=1

View File

@ -49,9 +49,9 @@ function teardown_file() {
# TODO replace with _send_email as soon as it supports DSN # TODO replace with _send_email as soon as it supports DSN
# TODO ref: https://github.com/jetmore/swaks/issues/41 # TODO ref: https://github.com/jetmore/swaks/issues/41
_nc_wrapper 'emails/nc_raw/dsn/unauthenticated' _nc_wrapper 'emails/nc_raw/dsn/unauthenticated.txt'
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 465' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 465'
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 587' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 587'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
_run_in_container grep "${LOG_DSN}" /var/log/mail/mail.log _run_in_container grep "${LOG_DSN}" /var/log/mail/mail.log
@ -62,7 +62,7 @@ function teardown_file() {
@test "should only send a DSN when requested from ports 465/587" { @test "should only send a DSN when requested from ports 465/587" {
export CONTAINER_NAME=${CONTAINER2_NAME} export CONTAINER_NAME=${CONTAINER2_NAME}
_nc_wrapper 'emails/nc_raw/dsn/unauthenticated' _nc_wrapper 'emails/nc_raw/dsn/unauthenticated.txt'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
# DSN requests can now only be made on ports 465 and 587, # DSN requests can now only be made on ports 465 and 587,
@ -74,8 +74,8 @@ function teardown_file() {
assert_failure assert_failure
# These ports are excluded via master.cf. # These ports are excluded via master.cf.
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 465' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 465'
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 587' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 587'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
_run_in_container grep "${LOG_DSN}" /var/log/mail/mail.log _run_in_container grep "${LOG_DSN}" /var/log/mail/mail.log
@ -85,9 +85,9 @@ function teardown_file() {
@test "should never send a DSN" { @test "should never send a DSN" {
export CONTAINER_NAME=${CONTAINER3_NAME} export CONTAINER_NAME=${CONTAINER3_NAME}
_nc_wrapper 'emails/nc_raw/dsn/unauthenticated' _nc_wrapper 'emails/nc_raw/dsn/unauthenticated.txt'
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 465' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 465'
_nc_wrapper 'emails/nc_raw/dsn/authenticated' '0.0.0.0 587' _nc_wrapper 'emails/nc_raw/dsn/authenticated.txt' '0.0.0.0 587'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
# DSN requests are rejected regardless of origin. # DSN requests are rejected regardless of origin.

View File

@ -38,7 +38,7 @@ function teardown_file() { _default_teardown ; }
@test "delivers mail to existing account" { @test "delivers mail to existing account" {
_wait_for_smtp_port_in_container _wait_for_smtp_port_in_container
_send_email --data 'existing/user1' # send a test email _send_email
# Verify delivery was successful, log line should look similar to: # Verify delivery was successful, log line should look similar to:
# postfix/lmtp[1274]: 0EA424ABE7D9: to=<user1@localhost.localdomain>, relay=127.0.0.1[127.0.0.1]:24, delay=0.13, delays=0.07/0.01/0.01/0.05, dsn=2.0.0, status=sent (250 2.0.0 <user1@localhost.localdomain> ixPpB+Zvv2P7BAAAUi6ngw Saved) # postfix/lmtp[1274]: 0EA424ABE7D9: to=<user1@localhost.localdomain>, relay=127.0.0.1[127.0.0.1]:24, delay=0.13, delays=0.07/0.01/0.01/0.05, dsn=2.0.0, status=sent (250 2.0.0 <user1@localhost.localdomain> ixPpB+Zvv2P7BAAAUi6ngw Saved)

View File

@ -26,11 +26,10 @@ function teardown_file() { _default_teardown ; }
# this test covers https://github.com/docker-mailserver/docker-mailserver/issues/681 # this test covers https://github.com/docker-mailserver/docker-mailserver/issues/681
@test "(Postfix) remove privacy details of the sender" { @test "(Postfix) remove privacy details of the sender" {
_send_email \ _send_email \
--port 587 -tls --auth LOGIN \ --port 587 -tls --auth PLAIN \
--auth-user user1@localhost.localdomain \ --auth-user user1@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--data 'privacy' --data 'privacy.txt'
assert_success
_run_until_success_or_timeout 120 _exec_in_container_bash '[[ -d /var/mail/localhost.localdomain/user1/new ]]' _run_until_success_or_timeout 120 _exec_in_container_bash '[[ -d /var/mail/localhost.localdomain/user1/new ]]'
assert_success assert_success

View File

@ -63,46 +63,43 @@ function setup_file() {
# TODO: Move to clamav tests (For use when ClamAV is enabled): # TODO: Move to clamav tests (For use when ClamAV is enabled):
# _repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /var/run/clamav/clamd.ctl # _repeat_in_container_until_success_or_timeout 60 "${CONTAINER_NAME}" test -e /var/run/clamav/clamd.ctl
# _send_email --from 'virus@external.tld' --data 'amavis/virus' # _send_email --from 'virus@external.tld' --data 'amavis/virus.txt'
# Required for 'delivers mail to existing alias': # Required for 'delivers mail to existing alias':
_send_email --to alias1@localhost.localdomain --data 'existing/alias-external' _send_email --to alias1@localhost.localdomain --header "Subject: Test Message existing-alias-external"
# Required for 'delivers mail to existing alias with recipient delimiter': # Required for 'delivers mail to existing alias with recipient delimiter':
_send_email --to alias1~test@localhost.localdomain --data 'existing/alias-recipient-delimiter' _send_email --to alias1~test@localhost.localdomain --header 'Subject: Test Message existing-alias-recipient-delimiter'
# Required for 'delivers mail to existing catchall': # Required for 'delivers mail to existing catchall':
_send_email --to wildcard@localdomain2.com --data 'existing/catchall-local' _send_email --to wildcard@localdomain2.com --header 'Subject: Test Message existing-catchall-local'
# Required for 'delivers mail to regexp alias': # Required for 'delivers mail to regexp alias':
_send_email --to test123@localhost.localdomain --data 'existing/regexp-alias-local' _send_email --to test123@localhost.localdomain --header 'Subject: Test Message existing-regexp-alias-local'
# Required for 'rejects mail to unknown user': # Required for 'rejects mail to unknown user':
_send_email --to nouser@localhost.localdomain --data 'non-existing-user' _send_email --expect-rejection --to nouser@localhost.localdomain
assert_failure
# Required for 'redirects mail to external aliases': # Required for 'redirects mail to external aliases':
_send_email --to bounce-always@localhost.localdomain --data 'existing/regexp-alias-external' _send_email --to bounce-always@localhost.localdomain
_send_email --to alias2@localhost.localdomain --data 'existing/alias-local' _send_email --to alias2@localhost.localdomain
# Required for 'rejects spam': # Required for 'rejects spam':
_send_email --from 'spam@external.tld' --data 'amavis/spam' _send_spam
# Required for 'delivers mail to existing account': # Required for 'delivers mail to existing account':
_send_email --data 'existing/user1' _send_email --header 'Subject: Test Message existing-user1'
assert_success
_send_email --to user2@otherdomain.tld _send_email --to user2@otherdomain.tld
assert_success
_send_email --to user3@localhost.localdomain _send_email --to user3@localhost.localdomain
assert_success _send_email --to added@localhost.localdomain --header 'Subject: Test Message existing-added'
_send_email --to added@localhost.localdomain --data 'existing/added' _send_email \
assert_success --to user1@localhost.localdomain \
_send_email --to user1@localhost.localdomain --data 'existing/user-and-cc-local-alias' --header 'Subject: Test Message existing-user-and-cc-local-alias' \
assert_success --cc 'alias2@localhost.localdomain'
_send_email --data 'sieve/spam-folder' _send_email --data 'sieve/spam-folder.txt'
assert_success _send_email --to user2@otherdomain.tld --data 'sieve/pipe.txt'
_send_email --to user2@otherdomain.tld --data 'sieve/pipe'
assert_success
_run_in_container_bash 'sendmail root < /tmp/docker-mailserver-test/emails/sendmail/root-email.txt' _run_in_container_bash 'sendmail root < /tmp/docker-mailserver-test/emails/sendmail/root-email.txt'
assert_success assert_success
} }
function _unsuccessful() { function _unsuccessful() {
_send_email --port 465 --auth "${1}" --auth-user "${2}" --auth-password wrongpassword _send_email --expect-rejection --port 465 --auth "${1}" --auth-user "${2}" --auth-password wrongpassword --quit-after AUTH
assert_failure assert_failure
assert_output --partial 'authentication failed' assert_output --partial 'authentication failed'
assert_output --partial 'No authentication type succeeded' assert_output --partial 'No authentication type succeeded'
@ -110,7 +107,6 @@ function _unsuccessful() {
function _successful() { function _successful() {
_send_email --port 465 --auth "${1}" --auth-user "${2}" --auth-password mypassword --quit-after AUTH _send_email --port 465 --auth "${1}" --auth-user "${2}" --auth-password mypassword --quit-after AUTH
assert_success
assert_output --partial 'Authentication successful' assert_output --partial 'Authentication successful'
} }

View File

@ -24,12 +24,12 @@ function teardown_file() { _default_teardown ; }
} }
@test 'authentication works' { @test 'authentication works' {
_nc_wrapper 'auth/pop3-auth' '-w 1 0.0.0.0 110' _nc_wrapper 'auth/pop3-auth.txt' '-w 1 0.0.0.0 110'
assert_success assert_success
} }
@test 'added user authentication works' { @test 'added user authentication works' {
_nc_wrapper 'auth/added-pop3-auth' '-w 1 0.0.0.0 110' _nc_wrapper 'auth/added-pop3-auth.txt' '-w 1 0.0.0.0 110'
assert_success assert_success
} }

View File

@ -21,7 +21,7 @@ function setup_file() {
function teardown_file() { _default_teardown ; } function teardown_file() { _default_teardown ; }
@test '(Dovecot) LDAP RIMAP connection and authentication works' { @test '(Dovecot) LDAP RIMAP connection and authentication works' {
_nc_wrapper 'auth/imap-auth' '-w 1 0.0.0.0 143' _nc_wrapper 'auth/imap-auth.txt' '-w 1 0.0.0.0 143'
assert_success assert_success
} }
@ -31,8 +31,8 @@ function teardown_file() { _default_teardown ; }
} }
@test '(SASLauthd) RIMAP SMTP authentication works' { @test '(SASLauthd) RIMAP SMTP authentication works' {
_send_email \ _send_email --expect-rejection \
--auth LOGIN \ --auth PLAIN \
--auth-user user1@localhost.localdomain \ --auth-user user1@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--quit-after AUTH --quit-after AUTH
@ -41,20 +41,18 @@ function teardown_file() { _default_teardown ; }
_send_email \ _send_email \
--port 465 \ --port 465 \
--auth LOGIN \ --auth PLAIN \
--auth-user user1@localhost.localdomain \ --auth-user user1@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--quit-after AUTH --quit-after AUTH
assert_success
assert_output --partial 'Authentication successful' assert_output --partial 'Authentication successful'
_send_email \ _send_email \
--port 587 \ --port 587 \
--auth LOGIN \ --auth PLAIN \
--auth-user user1@localhost.localdomain \ --auth-user user1@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--quit-after AUTH --quit-after AUTH
assert_success
assert_output --partial 'Authentication successful' assert_output --partial 'Authentication successful'
} }

View File

@ -248,7 +248,7 @@ function teardown() {
# dovecot # dovecot
@test "dovecot: ldap imap connection and authentication works" { @test "dovecot: ldap imap connection and authentication works" {
_nc_wrapper 'auth/imap-ldap-auth' '-w 1 0.0.0.0 143' _nc_wrapper 'auth/imap-ldap-auth.txt' '-w 1 0.0.0.0 143'
assert_success assert_success
} }
@ -326,25 +326,26 @@ function teardown() {
@test "spoofing (with LDAP): rejects sender forging" { @test "spoofing (with LDAP): rejects sender forging" {
_wait_for_smtp_port_in_container_to_respond dms-test_ldap _wait_for_smtp_port_in_container_to_respond dms-test_ldap
_send_email \ _send_email --expect-rejection \
--port 465 -tlsc --auth LOGIN \ --port 465 -tlsc --auth PLAIN \
--auth-user some.user@localhost.localdomain \ --auth-user some.user@localhost.localdomain \
--auth-password secret \ --auth-password secret \
--ehlo mail \ --ehlo mail \
--from ldap@localhost.localdomain \ --from ldap@localhost.localdomain \
--data 'auth/ldap-smtp-auth-spoofed' --data 'auth/ldap-smtp-auth-spoofed.txt'
assert_failure
assert_output --partial 'Sender address rejected: not owned by user' assert_output --partial 'Sender address rejected: not owned by user'
} }
@test "spoofing (with LDAP): accepts sending as alias" { @test "spoofing (with LDAP): accepts sending as alias" {
_send_email \ _send_email \
--port 465 -tlsc --auth LOGIN \ --port 465 -tlsc --auth PLAIN \
--auth-user some.user@localhost.localdomain \ --auth-user some.user@localhost.localdomain \
--auth-password secret \ --auth-password secret \
--ehlo mail \ --ehlo mail \
--from postmaster@localhost.localdomain \ --from postmaster@localhost.localdomain \
--to some.user@localhost.localdomain \ --to some.user@localhost.localdomain \
--data 'auth/ldap-smtp-auth-spoofed-alias' --data 'auth/ldap-smtp-auth-spoofed-alias.txt'
assert_output --partial 'End data with' assert_output --partial 'End data with'
} }
@ -353,20 +354,21 @@ function teardown() {
# Template used has invalid AUTH: https://github.com/docker-mailserver/docker-mailserver/pull/3006#discussion_r1073321432 # Template used has invalid AUTH: https://github.com/docker-mailserver/docker-mailserver/pull/3006#discussion_r1073321432
skip 'TODO: This test seems to have been broken from the start (?)' skip 'TODO: This test seems to have been broken from the start (?)'
_send_email \ _send_email --expect-rejection \
--port 465 -tlsc --auth LOGIN \ --port 465 -tlsc --auth PLAIN \
--auth-user some.user.email@localhost.localdomain \ --auth-user some.user.email@localhost.localdomain \
--auth-password secret \ --auth-password secret \
--ehlo mail \ --ehlo mail \
--from randomspoofedaddress@localhost.localdomain \ --from randomspoofedaddress@localhost.localdomain \
--to some.user@localhost.localdomain \ --to some.user@localhost.localdomain \
--data 'auth/ldap-smtp-auth-spoofed-sender-with-filter-exception' --data 'auth/ldap-smtp-auth-spoofed-sender-with-filter-exception.txt'
assert_failure
assert_output --partial 'Sender address rejected: not owned by user' assert_output --partial 'Sender address rejected: not owned by user'
} }
@test "saslauthd: ldap smtp authentication" { @test "saslauthd: ldap smtp authentication" {
_send_email \ _send_email --expect-rejection \
--auth LOGIN \ --auth PLAIN \
--auth-user some.user@localhost.localdomain \ --auth-user some.user@localhost.localdomain \
--auth-password wrongpassword \ --auth-password wrongpassword \
--quit-after AUTH --quit-after AUTH
@ -379,12 +381,11 @@ function teardown() {
--auth-user some.user@localhost.localdomain \ --auth-user some.user@localhost.localdomain \
--auth-password secret \ --auth-password secret \
--quit-after AUTH --quit-after AUTH
assert_success
assert_output --partial 'Authentication successful' assert_output --partial 'Authentication successful'
_send_email \ _send_email \
--port 587 -tls \ --port 587 -tls \
--auth LOGIN \ --auth PLAIN \
--auth-user some.user@localhost.localdomain \ --auth-user some.user@localhost.localdomain \
--auth-password secret \ --auth-password secret \
--quit-after AUTH --quit-after AUTH

View File

@ -0,0 +1,66 @@
load "${REPOSITORY_ROOT}/test/helper/setup"
load "${REPOSITORY_ROOT}/test/helper/common"
BATS_TEST_NAME_PREFIX='[OAuth2] '
CONTAINER1_NAME='dms-test_oauth2'
CONTAINER2_NAME='dms-test_oauth2_provider'
function setup_file() {
export DMS_TEST_NETWORK='test-network-oauth2'
export DMS_DOMAIN='example.test'
export FQDN_MAIL="mail.${DMS_DOMAIN}"
export FQDN_OAUTH2="oauth2.${DMS_DOMAIN}"
# Link the test containers to separate network:
# NOTE: If the network already exists, test will fail to start.
docker network create "${DMS_TEST_NETWORK}"
# Setup local oauth2 provider service:
docker run --rm -d --name "${CONTAINER2_NAME}" \
--hostname "${FQDN_OAUTH2}" \
--network "${DMS_TEST_NETWORK}" \
--volume "${REPOSITORY_ROOT}/test/config/oauth2/:/app/" \
docker.io/library/python:latest \
python /app/provider.py
_run_until_success_or_timeout 20 sh -c "docker logs ${CONTAINER2_NAME} 2>&1 | grep 'Starting server'"
#
# Setup DMS container
#
# Add OAUTH2 configuration so that Dovecot can reach out to our mock provider (CONTAINER2)
local ENV_OAUTH2_CONFIG=(
--env ENABLE_OAUTH2=1
--env OAUTH2_INTROSPECTION_URL=http://oauth2.example.test/userinfo/
)
export CONTAINER_NAME=${CONTAINER1_NAME}
local CUSTOM_SETUP_ARGUMENTS=(
"${ENV_OAUTH2_CONFIG[@]}"
--hostname "${FQDN_MAIL}"
--network "${DMS_TEST_NETWORK}"
)
_init_with_defaults
_common_container_setup 'CUSTOM_SETUP_ARGUMENTS'
_wait_for_tcp_port_in_container 143
# Set default implicit container fallback for helpers:
export CONTAINER_NAME=${CONTAINER1_NAME}
}
function teardown_file() {
docker rm -f "${CONTAINER1_NAME}" "${CONTAINER2_NAME}"
docker network rm "${DMS_TEST_NETWORK}"
}
@test "oauth2: imap connect and authentication works" {
# An initial connection needs to be made first, otherwise the auth attempt fails
_run_in_container_bash 'nc -vz 0.0.0.0 143'
_nc_wrapper 'auth/imap-oauth2-auth.txt' '-w 1 0.0.0.0 143'
assert_output --partial 'Examine completed'
}

View File

@ -80,12 +80,12 @@ function teardown_file() { _default_teardown ; }
} }
@test "imap: authentication works" { @test "imap: authentication works" {
_nc_wrapper 'auth/imap-auth' '-w 1 0.0.0.0 143' _nc_wrapper 'auth/imap-auth.txt' '-w 1 0.0.0.0 143'
assert_success assert_success
} }
@test "imap: added user authentication works" { @test "imap: added user authentication works" {
_nc_wrapper 'auth/added-imap-auth' '-w 1 0.0.0.0 143' _nc_wrapper 'auth/added-imap-auth.txt' '-w 1 0.0.0.0 143'
assert_success assert_success
} }
@ -293,13 +293,13 @@ EOF
# An authenticated user cannot use an envelope sender (MAIL FROM) # An authenticated user cannot use an envelope sender (MAIL FROM)
# address they do not own according to `main.cf:smtpd_sender_login_maps` lookup # address they do not own according to `main.cf:smtpd_sender_login_maps` lookup
_send_email \ _send_email --expect-rejection \
--port 465 -tlsc --auth LOGIN \ --port 465 -tlsc --auth PLAIN \
--auth-user added@localhost.localdomain \ --auth-user added@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--ehlo mail \ --ehlo mail \
--from user2@localhost.localdomain \ --from user2@localhost.localdomain \
--data 'auth/added-smtp-auth-spoofed' --data 'auth/added-smtp-auth-spoofed.txt'
assert_output --partial 'Sender address rejected: not owned by user' assert_output --partial 'Sender address rejected: not owned by user'
} }
@ -310,12 +310,12 @@ EOF
# to each table. Address is authorized when a result that maps to # to each table. Address is authorized when a result that maps to
# the DMS account is returned. # the DMS account is returned.
_send_email \ _send_email \
--port 465 -tlsc --auth LOGIN \ --port 465 -tlsc --auth PLAIN \
--auth-user user1@localhost.localdomain \ --auth-user user1@localhost.localdomain \
--auth-password mypassword \ --auth-password mypassword \
--ehlo mail \ --ehlo mail \
--from alias1@localhost.localdomain \ --from alias1@localhost.localdomain \
--data 'auth/added-smtp-auth-spoofed-alias' --data 'auth/added-smtp-auth-spoofed-alias.txt'
assert_success assert_success
assert_output --partial 'End data with' assert_output --partial 'End data with'
} }

View File

@ -20,7 +20,7 @@ function setup_file() {
function teardown_file() { _default_teardown ; } function teardown_file() { _default_teardown ; }
@test 'should successfully deliver mail' { @test 'should successfully deliver mail' {
_send_email --data 'existing/user1' _send_email --header 'Subject: Test Message existing-user1'
_wait_for_empty_mail_queue_in_container _wait_for_empty_mail_queue_in_container
# Should be successfully sent (received) by Postfix: # Should be successfully sent (received) by Postfix:
@ -31,7 +31,7 @@ function teardown_file() { _default_teardown ; }
# Verify successful delivery via Dovecot to `/var/mail` account by searching for the subject: # Verify successful delivery via Dovecot to `/var/mail` account by searching for the subject:
_repeat_in_container_until_success_or_timeout 20 "${CONTAINER_NAME}" grep -R \ _repeat_in_container_until_success_or_timeout 20 "${CONTAINER_NAME}" grep -R \
'Subject: Test Message existing-user1.txt' \ 'Subject: Test Message existing-user1' \
'/var/mail/localhost.localdomain/user1/new/' '/var/mail/localhost.localdomain/user1/new/'
assert_success assert_success
_should_output_number_of_lines 1 _should_output_number_of_lines 1