Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docs/content/config/advanced/auth-ldap.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ If your directory doesn't have the [postfix-book schema](https://github.com/vari
- DOVECOT_USER_ATTRS=mailHomeDirectory=home,mailUidNumber=uid,mailGidNumber=gid,mailStorageDirectory=mail
- DOVECOT_PASS_ATTRS=uniqueIdentifier=user,userPassword=password
- DOVECOT_USER_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
- DOVECOT_ITERATE_FILTER=(objectClass=PostfixBookMailAccount)
- DOVECOT_ITERATE_ATTRS=uniqueIdentifier=user
```

???+ example
Expand All @@ -88,6 +90,8 @@ If your directory doesn't have the [postfix-book schema](https://github.com/vari
- DOVECOT_PASS_ATTRS=uid=user,userPassword=password
- DOVECOT_USER_ATTRS=homeDirectory=home,qmailUID=uid,qmailGID=gid,mailMessageStore=mail
- DOVECOT_USER_FILTER=(&(objectClass=qmailUser)(uid=%u)(accountStatus=active))
- DOVECOT_ITERATE_FILTER=(objectClass=qmailUser)
- DOVECOT_ITERATE_ATTRS=uid=user
```

The LDAP server configuration for dovecot will be taken mostly from postfix, other options can be found in [the environment section in the docs][docs-environment].
Expand Down Expand Up @@ -181,6 +185,8 @@ The changes on the configurations necessary to work with Active Directory (**onl
# At the moment to be able to use %{ldap:uidNumber}, a manual bug fix as described above must be used. Otherwise %{ldap:uidNumber} %{ldap:uidNumber} must be replaced by the hard-coded value 5000.
- DOVECOT_USER_ATTRS==uid=%{ldap:uidNumber},=gid=5000,=home=/var/mail/%Ln,=mail=maildir:~/Maildir
- DOVECOT_PASS_ATTRS=sAMAccountName=user,userPassword=password
- DOVECOT_ITERATE_FILTER=(objectClass=person)
- DOVECOT_ITERATE_ATTRS=uid=user
- SASLAUTHD_LDAP_FILTER=(&(sAMAccountName=%U)(objectClass=person))
```

Expand Down Expand Up @@ -233,6 +239,8 @@ The changes on the configurations necessary to work with Active Directory (**onl
- DOVECOT_USER_FILTER=(&(objectClass=inetOrgPerson)(mail=%u))
- DOVECOT_PASS_ATTRS=uid=user,userPassword=password
- DOVECOT_USER_ATTRS==home=/var/mail/%{ldap:uid},=mail=maildir:~/Maildir,uidNumber=uid,gidNumber=gid
- DOVECOT_ITERATE_FILTER=(objectClass=PostfixBookMailAccount)
- DOVECOT_ITERATE_ATTRS=mail=user
# <<< Dovecot LDAP Integration

# >>> SASL LDAP Authentication
Expand Down
10 changes: 10 additions & 0 deletions docs/content/config/environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,16 @@ The following variables overwrite the default values for ```/etc/dovecot/dovecot
- e.g. `(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))`
- **empty** => same as `DOVECOT_USER_FILTER`

##### DOVECOT_ITERATE_FILTER

- e.g. `(objectClass=PostfixBookMailAccount)`
- The filter to apply to list all users.

##### DOVECOT_ITERATE_ATTRS

- e.g. `uniqueIdentifier=user` or `mail=user`
- Specify the attribute to use while listing all users.

##### DOVECOT_PASS_ATTRS

- e.g. `uid=user,userPassword=password`
Expand Down
2 changes: 2 additions & 0 deletions docs/content/examples/tutorials/basic-installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ services:
- LDAP_QUERY_FILTER_DOMAIN=(|(&(mail=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailGroupMember=*@%s)(objectClass=PostfixBookMailAccount)(mailEnabled=TRUE))(&(mailalias=*@%s)(objectClass=PostfixBookMailForward)))
- DOVECOT_PASS_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
- DOVECOT_USER_FILTER=(&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
- DOVECOT_ITERATE_FILTER=(objectClass=PostfixBookMailAccount)
- DOVECOT_ITERATE_ATTRS=mail=user
- ENABLE_SASLAUTHD=1
- SASLAUTHD_MECHANISMS=ldap
- SASLAUTHD_LDAP_SERVER=ldap
Expand Down
2 changes: 2 additions & 0 deletions target/dovecot/dovecot-ldap.conf.ext
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ pass_attrs = uniqueIdentifier=user,userPassword=password
pass_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
user_attrs = mailHomeDirectory=home,mailUidNumber=uid,mailGidNumber=gid,mailStorageDirectory=mail
user_filter = (&(objectClass=PostfixBookMailAccount)(uniqueIdentifier=%n))
iterate_filter = (objectClass=PostfixBookMailAccount)
iterate_attrs = mail=user
Comment on lines +12 to +13
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On production I had removed the user patches lines to insert the following lines

I am starting to think that only adding ENVs like DOVECOT_ITERATE_ATTRS may not be enougth to have the magic work. Maybe default values in this file are an essential part too

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is not working for you?

You just want the test-cases you added to pass with the expected output correct? I'll ensure that happens 👍

auth_bind = no
47 changes: 47 additions & 0 deletions test/tests/serial/mail_with_ldap.bats
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,53 @@ function teardown_file() {
done
}


@test "dovecot: ldap email listing works" {
_run_in_container doveadm user '*'
assert_success
assert_line --index 0 '[email protected]'
assert_line --index 1 '[email protected]'
assert_line --index 2 '[email protected]'
_should_output_number_of_lines 3
}

@test "dovecot: (ENV DOVECOT_ITERATE_ATTRS=uniqueIdentifier=user) ldap email listing works" {
local CUSTOM_SETUP_ARGUMENTS=(
--env DOVECOT_ITERATE_ATTRS='uniqueIdentifier=user'
)
Comment on lines +172 to +174
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for reasons that I ignore, this does not seem to give the options to the container creation process

Any help would be very welcome 🙏🏻

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You will need to provide the array CUSTOM_SETUP_ARGUMENTS on container startup to the function that creates the container. Functions like _run_in_container do not take it into account.

If you want to have it added to the ENV of the container, you'll need to do so at the top of the file where the container is created I guess (or wherever it is created). Probably

https://github.com/docker-mailserver/docker-mailserver/pull/3426/files#diff-664e916443d73f328b2c0c61c3a1aca1de5b968cfb03316012765971cbb5980bR79

and

https://github.com/docker-mailserver/docker-mailserver/pull/3426/files#diff-664e916443d73f328b2c0c61c3a1aca1de5b968cfb03316012765971cbb5980bR93

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we need to create a new container instance when we want to use different ENV like your test-cases do.

I've converted the test file into the new format we use, but it is the kind that sets all containers up in the main setup() method, whereas you'll see some other tests elsewhere like hostname.bats needs to run different variations for different test cases so each test-case is making it's own container instance, and calling many functions as "test-cases" (a workaround I opted for).

We could technically have multiple .bats files instead, but for such small test-cases like yours that seems unnecessary. I will adapt this LDAP test to support both approaches, but the main annoyance I had was with the ENV setup / sharing.

Technically you could right now define a common base ENV and combine like done here:

local ENABLED_PROCESS_LIST=(
"${CORE_PROCESS_LIST[@]}"
"${ENV_PROCESS_LIST[@]}"
)

Then you can create a container with different ENV like this small test-case:

# Split into separate test case for the benefit of minimizing CPU + RAM overhead of clamd.
# NOTE: Does not reduce test time of previous test case. Adds 10 seconds to test time.
@test "(enabled ENV) should restart clamd when killed" {
export CONTAINER_NAME=${CONTAINER3_NAME}
local CONTAINER_ARGS_ENV_CUSTOM=(
--env ENABLE_CLAMAV=1
)
_init_with_defaults
_common_container_setup 'CONTAINER_ARGS_ENV_CUSTOM'
_should_restart_when_killed 'clamd'
_should_stop_cleanly
}

You'd just expand an array like in the prior snippet I showed for sharing the base ENV each container is needing. Do note that you don't have to call it CUSTOM_SETUP_ARGUMENTS (although you should when you can), we just have to match the string value of the variable name that is passed to _common_container_setup().

Plan is that after converting all tests to the new format, to do another pass that moves to compose.yaml, which may instead rely on ENV files or a different way to modularize these config variants.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that a PR is about to get merged which changes the test uniqueIdentifier to userID (uid).

Although my goal is iterating towards mail attribute, at least as the login name but presently the test and DMS are not properly configured for this, hence why your PR is delayed. I'd like to get that transition for our LDAP tests and docs addressed first, but am happy to go ahead with this Dovecot support for v13 after I can be more confident in our LDAP support and test coverage :)


_run_in_container doveadm user '*'
assert_success
assert_line --index 0 'some.user'
assert_line --index 1 'some.other.user'
assert_line --index 2 'some.user.id'
_should_output_number_of_lines 3
}

@test "dovecot: (ENV DOVECOT_ITERATE_FILTER=(objectClass=PostfixBookMailAccount)) ldap email listing works" {
local CUSTOM_SETUP_ARGUMENTS=(
--env DOVECOT_ITERATE_FILTER='(objectClass=PostfixBookMailAccount)'
)

_run_in_container doveadm user '*'
assert_success
assert_line --index 0 '[email protected]'
assert_line --index 1 '[email protected]'
assert_line --index 2 '[email protected]'
_should_output_number_of_lines 3
}
Comment on lines +184 to +195
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's an example of what this would look like from the advice given in my review feedback:

@test "dovecot: (ENV DOVECOT_ITERATE_FILTER=(objectClass=PostfixBookMailAccount)) ldap email listing works" {
  # Container setup:
  export CONTAINER_NAME='dms-test_ldap_dovecot-iter3'
  local CONTAINER_ARGS_ENV_CUSTOM=(
    "${CONFIG_CONTAINER_BASE[@]}"
    --env DOVECOT_ITERATE_FILTER='(objectClass=PostfixBookMailAccount)'
  )
  _init_with_defaults
  _common_container_setup 'CONTAINER_ARGS_ENV_CUSTOM'

  # Actual test-case:
  _run_in_container doveadm user '*'
  assert_success
  assert_line --index 0 '[email protected]'
  assert_line --index 1 '[email protected]'
  assert_line --index 2 '[email protected]'
  _should_output_number_of_lines 3

  # Cleanup, removes test-case container:
  _default_teardown
}

The cleanup is just force removing the container:

# Can be used in BATS' `teardown_file` function as a default value.
#
# @param ${1} = container name [OPTIONAL]
function _default_teardown() {
local TARGET_CONTAINER_NAME=${1:-${CONTAINER_NAME}}
docker rm -f "${TARGET_CONTAINER_NAME}"
}

Setup is like we do in setup(), except we need to export the custom args as a common base var to expand / import here. It's important to give each container a unique name to identify it, I chose to use the name variant dovecot-iter3 as it's the 3rd test-case container for testing against that ENV (or 2nd if we don't create a separate container for the default test).

Setting the name will ensure the helper methods used will know which container to use implicitly.


@test "dovecot: (ENV DOVECOT_ITERATE_FILTER=(uniqueIdentifier=some.user.id)) ldap email listing works" {
local CUSTOM_SETUP_ARGUMENTS=(
--env DOVECOT_ITERATE_FILTER='(uniqueIdentifier=some.user.id)'
)

_run_in_container doveadm user '*'
assert_success
assert_line --index 0 '[email protected]'
_should_output_number_of_lines 1
}

# dovecot
@test "dovecot: ldap imap connection and authentication works" {
_run_in_container_bash 'nc -w 1 0.0.0.0 143 < /tmp/docker-mailserver-test/auth/imap-ldap-auth.txt'
Expand Down