If you develop software for larger organizations one big aspect is integrating it with existing infrastructure. While you may prefer simple deployments of services in docker containers a customer may want you to deploy to their wildfly infrastructure for example.
One common case of infrastructure is an Active Directory (AD) or plain LDAP service used for organization wide authentication and authorization. As a small company we do not have such an infrastructure ourselves and it would not be a great idea to use it for development anyway.
So how do you develop and test your authentication module without an AD being available for you?
Fortunately, nowadays this is relatively easy using tools like Docker and Samba. Let us see how to put such a development infrastructure up and where the pitfalls are.
Running Samba in a Container
Samba cannot only serve windows shares or act as an domain controller for Microsoft Windows based networks but includes a full AD implementation with proper LDAP support. It takes a small amount of work besides installing Samba in a container to set it up, so we have two small shell scripts for setup and launch in a container. I think most of the Dockerfile and scripts should be self-explanatory and straightforward:
Dockerfile
:
FROM ubuntu:20.04
RUN DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install samba krb5-config winbind smbclient
RUN DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install iproute2
RUN DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install openssl
RUN DEBIAN_FRONTEND=noninteractive apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install vim
RUN rm /etc/krb5.conf
RUN mkdir -p /opt/ad-scripts
WORKDIR /opt/ad-scripts
CMD chmod +x *.sh && ./samba-ad-setup.sh && ./samba-ad-run.sh
samba-ad-setup.sh
:
#!/bin/bash
set -e
info () {
echo "[INFO] $@"
}
info "Running setup"
# Check if samba is setup
[ -f /var/lib/samba/.setup ] && info "Already setup..." && exit 0
info "Provisioning domain controller..."
info "Given admin password: ${SMB_ADMIN_PASSWORD}"
rm /etc/samba/smb.conf
samba-tool domain provision\
--server-role=dc\
--use-rfc2307\
--dns-backend=SAMBA_INTERNAL\
--realm=`hostname`\
--domain=DEV-AD\
--adminpass=${SMB_ADMIN_PASSWORD}
mv /etc/samba/smb.conf /var/lib/samba/private/smb.conf
touch /var/lib/samba/.setup
Using samba-ad-run.sh
we start samba directly instead of running it as a service which you would do outside a container:
#!/bin/bash
set -e
[ -f /var/lib/samba/.setup ] || {
>&2 echo "[ERROR] Samba is not setup yet, which should happen automatically. Look for errors!"
exit 127
}
samba -i -s /var/lib/samba/private/smb.conf
With the scripts and the Dockerfile in place you can simply build the container image using a command like
docker build -t dev-ad -f Dockerfile .
We then run it like follows and use the local mounts to preserve the data in the AD we will be using for testing and toying around:
docker run --name dev-ad --hostname ldap.schneide.dev --privileged -p 636:636 -e SMB_ADMIN_PASSWORD=admin123! -v $PWD/:/opt/ad-scripts -v $PWD/samba-data:/var/lib/samba dev-ad
To have everything running seamlessly you should add the specified hostname – ldap.schneide.dev
in our example – to /etc/hosts
so that all tools work as expected and like it was a real AD host somewhere.
Testing our setup
Now of course you may want to check if your development AD works as expected and maybe add some groups and users which you need for your implementation to work.
While there are a bunch of tools for working with an AD/LDAP I found the old and sturdy LdapAdmin the easiest and most straightforward to use. It comes as one self-contained executable file (downloadable from Sourceforge) ready to use without installation or other hassles.
After getting the container and LdapAdmin up and running and logging in you should see something like this below:

Then you can browse and edit your active directory to fit your needs allowing you to develop your authentication and authorization module based on LDAP.
I hope you found the above useful for you development setup.
I have followed all the steps, but I’m getting an error message “/usr/sbin/samba_dnsupdate: ERROR: Record already exist; record could not be added. zone[ldap.act.local] name[_ldap._tcp.Default-First-Site-Name._sites.ForestDnsZones] dnsupdate_nameupdate_done: Failed DNS update with exit code 29”
I am getting the same errors but as far as I can see they do not impact the functionality of the AD/LDAP service.
I’m trying to login through the LdapAdmin tool but I keep getting an error message.
LDAP error! Invalid Credentials: 80090308: LdapErr: DSID-0C0903A9, commnet: AcceptSecurityContext error, data 52e, v1db1.
The token supplied to the function is invalid.
In the Base filed I have: DC=ldap,DC=schneide,DC=dev
In the Username field I have: CN=Administrator,DC=ldap,DC=schneide,DC=dev
Also, when I try to run the samba-ad-run.sh I get the following error: “[ERROR] Samba is not setup yet, which should happen automatically. Look for errors!”.
Is there a way to get rid of the warning “The server you are trying to connect to is using a certificate which could not be verified! – Issuer certificate not found”?
In development I tend to avoid the certificate hassle by connecting unencrypted to the LDAP. Usually you have to allow unencrypted authentication using samba explicitly by setting
[global]
ldap server require strong auth = no
in /var/lib/samba/private/smb.conf of the container/samba. Do NOT use this setting for your production environment unless you are really knowing what you are doing.
Is there a way to connect to the LDAP tool using the domain name, instead of the full base DN path DC=ldap,DC=schneide,DC=dev?
Yes, for me using DEV-AD\Administrator or DEV-AD\ work fine, too.
I am able to add users to my LDAP server using LDAP Admin by using the Edit > New > User wizard. But when I try to create a new group using the Edit > New > Group wizard, I get the following error:
LDAP error! Object Class Violation: no structural object class provided
How can I create new groups in LDAP Admin?
I use right-click on a folder -> New -> Group… The shortcut is ctrl+G.
I tried right-click on a folder -> New -> Group and also the shortcut is ctrl+G.
LDAP error! Unwilling to perform: Failed to find a structural class for CN=testgroup,CN=Users,DC=test,DC=ad,DC=dev.
I tried creating a group using the shortcut ctrl+G, but I’m still getting an error message: LDAP error! Unwilling to perform: Failed to find a structural class for CN=testgroup,CN=Users,DC=test,DC=ad,DC=dev.
I ran step by step and landed in the following error
ERROR(): Provision failed – ProvisioningError: Your filesystem or build does not support posix ACLs, which s3fs requires. Try the mounting the filesystem with the ‘acl’ option.
File “/usr/lib/python3/dist-packages/samba/netcmd/domain.py”, line 487, in run
result = provision(self.logger,
File “/usr/lib/python3/dist-packages/samba/provision/__init__.py”, line 2341, in provision
provision_fill(samdb, secrets_ldb, logger, names, paths,
File “/usr/lib/python3/dist-packages/samba/provision/__init__.py”, line 1979, in provision_fill
setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.root_uid,
File “/usr/lib/python3/dist-packages/samba/provision/__init__.py”, line 1694, in setsysvolacl
raise ProvisioningError(“Your filesystem or build does not support posix ACLs, which s3fs requires.