Browse Source

Merge branch 'hotfix-1.1.9' into stable

Bertrand Gouny 8 years ago
parent
commit
aee872140c

+ 7 - 0
CHANGELOG.md

@@ -1,5 +1,12 @@
 # Changelog
 # Changelog
 
 
+## 1.1.9
+Add :
+  - LDAP_RFC2307BIS_SCHEMA option to use rfc2307bis schema instead of nis default schema
+  - KEEP_EXISTING_CONFIG option to not change the ldap config
+
+Update to light-baseimage:1.1.0 (debian stretch)
+
 ## 1.1.8
 ## 1.1.8
 Fix :
 Fix :
   - LDAP_ENFORCE_TLS is not working correctly #107
   - LDAP_ENFORCE_TLS is not working correctly #107

+ 14 - 9
Makefile

@@ -1,9 +1,7 @@
 NAME = osixia/openldap
 NAME = osixia/openldap
-VERSION = 1.1.8
+VERSION = 1.1.9
 
 
-.PHONY: all build build-nocache test tag_latest release
-
-all: build
+.PHONY: build build-nocache test tag-latest push push-latest release git-tag-version
 
 
 build:
 build:
 	docker build -t $(NAME):$(VERSION) --rm image
 	docker build -t $(NAME):$(VERSION) --rm image
@@ -14,10 +12,17 @@ build-nocache:
 test:
 test:
 	env NAME=$(NAME) VERSION=$(VERSION) bats test/test.bats
 	env NAME=$(NAME) VERSION=$(VERSION) bats test/test.bats
 
 
-tag_latest:
+tag-latest:
 	docker tag $(NAME):$(VERSION) $(NAME):latest
 	docker tag $(NAME):$(VERSION) $(NAME):latest
 
 
-release: build test tag_latest
-	@if ! docker images $(NAME) | awk '{ print $$2 }' | grep -q -F $(VERSION); then echo "$(NAME) version $(VERSION) is not yet built. Please run 'make build'"; false; fi
-	docker push $(NAME)
-	@echo "*** Don't forget to run 'twgit release/hotfix finish' :)"
+push:
+	docker push $(NAME):$(VERSION)
+
+push-latest:
+	docker push $(NAME):latest
+
+release: build test tag-latest push push-latest
+
+git-tag-version: release
+	git tag -a v$(VERSION) -m "v$(VERSION)"
+	git push origin v$(VERSION)

+ 51 - 24
README.md

@@ -4,14 +4,10 @@
 ![Docker Stars](https://img.shields.io/docker/stars/osixia/openldap.svg)
 ![Docker Stars](https://img.shields.io/docker/stars/osixia/openldap.svg)
 ![](https://images.microbadger.com/badges/image/osixia/openldap.svg)
 ![](https://images.microbadger.com/badges/image/osixia/openldap.svg)
 
 
-Latest release: 1.1.8 - OpenLDAP 2.4.40 -  [Changelog](CHANGELOG.md) | [Docker Hub](https://hub.docker.com/r/osixia/openldap/) 
+Latest release: 1.1.9 - OpenLDAP 2.4.44 -  [Changelog](CHANGELOG.md) | [Docker Hub](https://hub.docker.com/r/osixia/openldap/) 
 
 
 **A docker image to run OpenLDAP.**
 **A docker image to run OpenLDAP.**
 
 
-Note:
- - In the release 1.1.6 files `*.yaml.startup` have been renamed to `*.startup.yaml`
- - Due to issues #44 and #73 versions before 1.1.6 are not considered as stable and tags will be removed from docker hub.
-
 > OpenLDAP website : [www.openldap.org](http://www.openldap.org/)
 > OpenLDAP website : [www.openldap.org](http://www.openldap.org/)
 
 
 - [Contributing](#contributing)
 - [Contributing](#contributing)
@@ -38,7 +34,7 @@ Note:
 		- [Link environment file](#link-environment-file)
 		- [Link environment file](#link-environment-file)
 		- [Make your own image or extend this image](#make-your-own-image-or-extend-this-image)
 		- [Make your own image or extend this image](#make-your-own-image-or-extend-this-image)
 - [Advanced User Guide](#advanced-user-guide)
 - [Advanced User Guide](#advanced-user-guide)
-	- [Extend osixia/openldap:1.1.8 image](#extend-osixiaopenldap118-image)
+	- [Extend osixia/openldap:1.1.9 image](#extend-osixiaopenldap119-image)
 	- [Make your own openldap image](#make-your-own-openldap-image)
 	- [Make your own openldap image](#make-your-own-openldap-image)
 	- [Tests](#tests)
 	- [Tests](#tests)
 	- [Kubernetes](#kubernetes)
 	- [Kubernetes](#kubernetes)
@@ -56,7 +52,7 @@ If you find this image useful here's how you can help:
 ## Quick Start
 ## Quick Start
 Run OpenLDAP docker image:
 Run OpenLDAP docker image:
 
 
-	docker run --name my-openldap-container --detach osixia/openldap:1.1.8
+	docker run --name my-openldap-container --detach osixia/openldap:1.1.9
 
 
 This start a new container with OpenLDAP running inside. Let's make the first search in our LDAP container:
 This start a new container with OpenLDAP running inside. Let's make the first search in our LDAP container:
 
 
@@ -92,7 +88,7 @@ It will create an empty ldap for the company **Example Inc.** and the domain **e
 By default the admin has the password **admin**. All those default settings can be changed at the docker command line, for example:
 By default the admin has the password **admin**. All those default settings can be changed at the docker command line, for example:
 
 
 	docker run --env LDAP_ORGANISATION="My Company" --env LDAP_DOMAIN="my-company.com" \
 	docker run --env LDAP_ORGANISATION="My Company" --env LDAP_DOMAIN="my-company.com" \
-	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.8
+	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.9
 
 
 #### Data persistence
 #### Data persistence
 
 
@@ -108,6 +104,31 @@ For more information about docker data volume, please refer to:
 
 
 Do not edit slapd.conf it's not used. To modify your server configuration use ldap utils: **ldapmodify / ldapadd / ldapdelete**
 Do not edit slapd.conf it's not used. To modify your server configuration use ldap utils: **ldapmodify / ldapadd / ldapdelete**
 
 
+#### Seed ldap database with ldif
+
+This image can load ldif files at startup with either `ldapadd` or `ldapmodify`.
+Mount `.ldif` in `/container/service/slapd/assets/config/bootstrap/ldif` directory if you want to overwrite image default boostrap ldif files or in `/container/service/slapd/assets/config/bootstrap/ldif/custom` (recommended) to extend image config.
+
+Files containing `changeType:` attributes will be loaded with `ldapmodify`.
+
+The startup script provide some substitution in bootstrap ldif files:
+`{{LDAP_BASE_DN }}` and `{{ LDAP_BACKEND }}` values are supported. Other `{{ * }}`
+substitution are left as is.
+
+Since startup script modifies `ldif` files, you **must** add `--copy-service`
+argument to entrypoint if you don't want to overwrite them.
+
+
+		# single file example:
+		docker run \
+      --volume ./bootstrap.ldif:/container/service/slapd/assets/config/bootstrap/ldif/50-bootstrap.ldif \
+      osixia/openldap:1.1.9 --copy-service
+
+		#directory example:
+		docker run \
+	     --volume ./lidf:/container/service/slapd/assets/config/bootstrap/ldif/custom \
+	     osixia/openldap:1.1.9 --copy-service
+
 ### Use an existing ldap database
 ### Use an existing ldap database
 
 
 This can be achieved by mounting host directories as volume.
 This can be achieved by mounting host directories as volume.
@@ -117,7 +138,7 @@ simply mount this directories as a volume to `/var/lib/ldap` and `/etc/ldap/slap
 
 
 	docker run --volume /data/slapd/database:/var/lib/ldap \
 	docker run --volume /data/slapd/database:/var/lib/ldap \
 	--volume /data/slapd/config:/etc/ldap/slapd.d
 	--volume /data/slapd/config:/etc/ldap/slapd.d
-	--detach osixia/openldap:1.1.8
+	--detach osixia/openldap:1.1.9
 
 
 You can also use data volume containers. Please refer to:
 You can also use data volume containers. Please refer to:
 > [https://docs.docker.com/engine/tutorials/dockervolumes/](https://docs.docker.com/engine/tutorials/dockervolumes/)
 > [https://docs.docker.com/engine/tutorials/dockervolumes/](https://docs.docker.com/engine/tutorials/dockervolumes/)
@@ -137,7 +158,7 @@ If you are looking for a simple solution to administrate your ldap server you ca
 #### Use auto-generated certificate
 #### Use auto-generated certificate
 By default, TLS is already configured and enabled, certificate is created using container hostname (it can be set by docker run --hostname option eg: ldap.example.org).
 By default, TLS is already configured and enabled, certificate is created using container hostname (it can be set by docker run --hostname option eg: ldap.example.org).
 
 
-	docker run --hostname ldap.my-company.com --detach osixia/openldap:1.1.8
+	docker run --hostname ldap.my-company.com --detach osixia/openldap:1.1.9
 
 
 #### Use your own certificate
 #### Use your own certificate
 
 
@@ -147,24 +168,24 @@ You can set your custom certificate at run time, by mounting a directory contain
 	--env LDAP_TLS_CRT_FILENAME=my-ldap.crt \
 	--env LDAP_TLS_CRT_FILENAME=my-ldap.crt \
 	--env LDAP_TLS_KEY_FILENAME=my-ldap.key \
 	--env LDAP_TLS_KEY_FILENAME=my-ldap.key \
 	--env LDAP_TLS_CA_CRT_FILENAME=the-ca.crt \
 	--env LDAP_TLS_CA_CRT_FILENAME=the-ca.crt \
-	--detach osixia/openldap:1.1.8
+	--detach osixia/openldap:1.1.9
 
 
 Other solutions are available please refer to the [Advanced User Guide](#advanced-user-guide)
 Other solutions are available please refer to the [Advanced User Guide](#advanced-user-guide)
 
 
 #### Disable TLS
 #### Disable TLS
 Add --env LDAP_TLS=false to the run command:
 Add --env LDAP_TLS=false to the run command:
 
 
-	docker run --env LDAP_TLS=false --detach osixia/openldap:1.1.8
+	docker run --env LDAP_TLS=false --detach osixia/openldap:1.1.9
 
 
 ### Multi master replication
 ### Multi master replication
 Quick example, with the default config.
 Quick example, with the default config.
 
 
 	#Create the first ldap server, save the container id in LDAP_CID and get its IP:
 	#Create the first ldap server, save the container id in LDAP_CID and get its IP:
-	LDAP_CID=$(docker run --hostname ldap.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.8)
+	LDAP_CID=$(docker run --hostname ldap.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.9)
 	LDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP_CID)
 	LDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP_CID)
 
 
 	#Create the second ldap server, save the container id in LDAP2_CID and get its IP:
 	#Create the second ldap server, save the container id in LDAP2_CID and get its IP:
-	LDAP2_CID=$(docker run --hostname ldap2.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.8)
+	LDAP2_CID=$(docker run --hostname ldap2.example.org --env LDAP_REPLICATION=true --detach osixia/openldap:1.1.9)
 	LDAP2_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP2_CID)
 	LDAP2_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP2_CID)
 
 
 	#Add the pair "ip hostname" to /etc/hosts on each containers,
 	#Add the pair "ip hostname" to /etc/hosts on each containers,
@@ -200,7 +221,7 @@ You may have some problems with mounted files on some systems. The startup scrip
 
 
 To fix that run the container with `--copy-service` argument :
 To fix that run the container with `--copy-service` argument :
 
 
-		docker run [your options] osixia/openldap:1.1.8 --copy-service
+		docker run [your options] osixia/openldap:1.1.9 --copy-service
 
 
 ### Debug
 ### Debug
 
 
@@ -209,11 +230,11 @@ Available levels are: `none`, `error`, `warning`, `info`, `debug` and `trace`.
 
 
 Example command to run the container in `debug` mode:
 Example command to run the container in `debug` mode:
 
 
-	docker run --detach osixia/openldap:1.1.8 --loglevel debug
+	docker run --detach osixia/openldap:1.1.9 --loglevel debug
 
 
 See all command line options:
 See all command line options:
 
 
-	docker run osixia/openldap:1.1.8 --help
+	docker run osixia/openldap:1.1.9 --help
 
 
 
 
 ## Environment Variables
 ## Environment Variables
@@ -245,6 +266,8 @@ Required and used for new ldap server only:
 - **LDAP_READONLY_USER_USERNAME** Read only user username. Defaults to `readonly`
 - **LDAP_READONLY_USER_USERNAME** Read only user username. Defaults to `readonly`
 - **LDAP_READONLY_USER_PASSWORD** Read only user password. Defaults to `readonly`
 - **LDAP_READONLY_USER_PASSWORD** Read only user password. Defaults to `readonly`
 
 
+- **LDAP_RFC2307BIS_SCHEMA** Use rfc2307bis schema instead of nis schema. Defaults to `false`
+
 Backend:
 Backend:
 - **LDAP_BACKEND**: Ldap backend. Defaults to `hdb` (In comming versions v1.2.x default will be mdb)
 - **LDAP_BACKEND**: Ldap backend. Defaults to `hdb` (In comming versions v1.2.x default will be mdb)
 
 
@@ -276,11 +299,15 @@ Replication options:
 
 
 	If you want to set this variable at docker run command add the tag `#PYTHON2BASH:` and convert the yaml in python:
 	If you want to set this variable at docker run command add the tag `#PYTHON2BASH:` and convert the yaml in python:
 
 
-		docker run --env LDAP_REPLICATION_HOSTS="#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']" --detach osixia/openldap:1.1.8
+		docker run --env LDAP_REPLICATION_HOSTS="#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']" --detach osixia/openldap:1.1.9
 
 
 	To convert yaml to python online: http://yaml-online-parser.appspot.com/
 	To convert yaml to python online: http://yaml-online-parser.appspot.com/
 
 
 Other environment variables:
 Other environment variables:
+- **KEEP_EXISTING_CONFIG**: Do not change the ldap config. Defaults to `false`
+	- if set to *true* with an existing database, config will remain unchanged. Image tls and replication config will not be run. The container can be started with LDAP_ADMIN_PASSWORD and LDAP_CONFIG_PASSWORD empty or filled with fake data.
+	- if set to *true* when bootstrapping a new database, bootstap ldif and schema will not be added and tls and replication config will not be run.
+
 - **LDAP_REMOVE_CONFIG_AFTER_SETUP**: delete config folder after setup. Defaults to `true`
 - **LDAP_REMOVE_CONFIG_AFTER_SETUP**: delete config folder after setup. Defaults to `true`
 - **LDAP_SSL_HELPER_PREFIX**: ssl-helper environment variables prefix. Defaults to `ldap`, ssl-helper first search config from LDAP_SSL_HELPER_* variables, before SSL_HELPER_* variables.
 - **LDAP_SSL_HELPER_PREFIX**: ssl-helper environment variables prefix. Defaults to `ldap`, ssl-helper first search config from LDAP_SSL_HELPER_* variables, before SSL_HELPER_* variables.
 
 
@@ -291,7 +318,7 @@ Other environment variables:
 Environment variables can be set by adding the --env argument in the command line, for example:
 Environment variables can be set by adding the --env argument in the command line, for example:
 
 
 	docker run --env LDAP_ORGANISATION="My company" --env LDAP_DOMAIN="my-company.com" \
 	docker run --env LDAP_ORGANISATION="My company" --env LDAP_DOMAIN="my-company.com" \
-	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.8
+	--env LDAP_ADMIN_PASSWORD="JonSn0w" --detach osixia/openldap:1.1.9
 
 
 Be aware that environment variable added in command line will be available at any time
 Be aware that environment variable added in command line will be available at any time
 in the container. In this example if someone manage to open a terminal in this container
 in the container. In this example if someone manage to open a terminal in this container
@@ -302,14 +329,14 @@ he will be able to read the admin password in clear text from environment variab
 For example if your environment files **my-env.yaml** and **my-env.startup.yaml** are in /data/ldap/environment
 For example if your environment files **my-env.yaml** and **my-env.startup.yaml** are in /data/ldap/environment
 
 
 	docker run --volume /data/ldap/environment:/container/environment/01-custom \
 	docker run --volume /data/ldap/environment:/container/environment/01-custom \
-	--detach osixia/openldap:1.1.8
+	--detach osixia/openldap:1.1.9
 
 
 Take care to link your environment files folder to `/container/environment/XX-somedir` (with XX < 99 so they will be processed before default environment files) and not  directly to `/container/environment` because this directory contains predefined baseimage environment files to fix container environment (INITRD, LANG, LANGUAGE and LC_CTYPE).
 Take care to link your environment files folder to `/container/environment/XX-somedir` (with XX < 99 so they will be processed before default environment files) and not  directly to `/container/environment` because this directory contains predefined baseimage environment files to fix container environment (INITRD, LANG, LANGUAGE and LC_CTYPE).
 
 
 Note: the container will try to delete the **\*.startup.yaml** file after the end of startup files so the file will also be deleted on the docker host. To prevent that : use --volume /data/ldap/environment:/container/environment/01-custom**:ro** or set all variables in **\*.yaml** file and don't use **\*.startup.yaml**:
 Note: the container will try to delete the **\*.startup.yaml** file after the end of startup files so the file will also be deleted on the docker host. To prevent that : use --volume /data/ldap/environment:/container/environment/01-custom**:ro** or set all variables in **\*.yaml** file and don't use **\*.startup.yaml**:
 
 
 	docker run --volume /data/ldap/environment/my-env.yaml:/container/environment/01-custom/env.yaml \
 	docker run --volume /data/ldap/environment/my-env.yaml:/container/environment/01-custom/env.yaml \
-	--detach osixia/openldap:1.1.8
+	--detach osixia/openldap:1.1.9
 
 
 #### Make your own image or extend this image
 #### Make your own image or extend this image
 
 
@@ -317,13 +344,13 @@ This is the best solution if you have a private registry. Please refer to the [A
 
 
 ## Advanced User Guide
 ## Advanced User Guide
 
 
-### Extend osixia/openldap:1.1.8 image
+### Extend osixia/openldap:1.1.9 image
 
 
 If you need to add your custom TLS certificate, bootstrap config or environment files the easiest way is to extends this image.
 If you need to add your custom TLS certificate, bootstrap config or environment files the easiest way is to extends this image.
 
 
 Dockerfile example:
 Dockerfile example:
 
 
-	FROM osixia/openldap:1.1.8
+	FROM osixia/openldap:1.1.9
 	MAINTAINER Your Name <[email protected]>
 	MAINTAINER Your Name <[email protected]>
 
 
 	ADD bootstrap /container/service/slapd/assets/config/bootstrap
 	ADD bootstrap /container/service/slapd/assets/config/bootstrap
@@ -345,7 +372,7 @@ Clone this project:
 Adapt Makefile, set your image NAME and VERSION, for example:
 Adapt Makefile, set your image NAME and VERSION, for example:
 
 
 	NAME = osixia/openldap
 	NAME = osixia/openldap
-	VERSION = 1.1.8
+	VERSION = 1.1.9
 
 
 	become:
 	become:
 	NAME = cool-guy/openldap
 	NAME = cool-guy/openldap

+ 4 - 1
example/docker-compose.yml

@@ -1,7 +1,7 @@
 version: '2'
 version: '2'
 services:
 services:
   openldap:
   openldap:
-    image: osixia/openldap:1.1.8
+    image: osixia/openldap:1.1.9
     container_name: openldap
     container_name: openldap
     environment:
     environment:
       LDAP_LOG_LEVEL: "256"
       LDAP_LOG_LEVEL: "256"
@@ -13,6 +13,7 @@ services:
       LDAP_READONLY_USER: "false"
       LDAP_READONLY_USER: "false"
       #LDAP_READONLY_USER_USERNAME: "readonly"
       #LDAP_READONLY_USER_USERNAME: "readonly"
       #LDAP_READONLY_USER_PASSWORD: "readonly"
       #LDAP_READONLY_USER_PASSWORD: "readonly"
+      LDAP_RFC2307BIS_SCHEMA: "false"
       LDAP_BACKEND: "hdb"
       LDAP_BACKEND: "hdb"
       LDAP_TLS: "true"
       LDAP_TLS: "true"
       LDAP_TLS_CRT_FILENAME: "ldap.crt"
       LDAP_TLS_CRT_FILENAME: "ldap.crt"
@@ -26,6 +27,7 @@ services:
       #LDAP_REPLICATION_CONFIG_SYNCPROV: "binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="60 +" timeout=1 starttls=critical"
       #LDAP_REPLICATION_CONFIG_SYNCPROV: "binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="60 +" timeout=1 starttls=critical"
       #LDAP_REPLICATION_DB_SYNCPROV: "binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical"
       #LDAP_REPLICATION_DB_SYNCPROV: "binddn="cn=admin,$LDAP_BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$LDAP_BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="60 +" timeout=1 starttls=critical"
       #LDAP_REPLICATION_HOSTS: "#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']"
       #LDAP_REPLICATION_HOSTS: "#PYTHON2BASH:['ldap://ldap.example.org','ldap://ldap2.example.org']"
+      KEEP_EXISTING_CONFIG: "false"
       LDAP_REMOVE_CONFIG_AFTER_SETUP: "true"
       LDAP_REMOVE_CONFIG_AFTER_SETUP: "true"
       LDAP_SSL_HELPER_PREFIX: "ldap"
       LDAP_SSL_HELPER_PREFIX: "ldap"
     tty: true
     tty: true
@@ -37,6 +39,7 @@ services:
     ports:
     ports:
       - "389:389"
       - "389:389"
       - "636:636"
       - "636:636"
+    domainname: "example.org" # important: same as hostname
     hostname: "example.org"
     hostname: "example.org"
   phpldapadmin:
   phpldapadmin:
     image: osixia/phpldapadmin:latest
     image: osixia/phpldapadmin:latest

+ 1 - 1
example/extend-osixia-openldap/Dockerfile

@@ -1,4 +1,4 @@
-FROM osixia/openldap:1.1.8
+FROM osixia/openldap:1.1.9
 MAINTAINER Your Name <[email protected]>
 MAINTAINER Your Name <[email protected]>
 
 
 ADD bootstrap /container/service/slapd/assets/config/bootstrap
 ADD bootstrap /container/service/slapd/assets/config/bootstrap

+ 5 - 1
example/kubernetes/simple/ldap-deployment.yaml

@@ -13,7 +13,7 @@ spec:
     spec:
     spec:
       containers:
       containers:
         - name: ldap
         - name: ldap
-          image: osixia/openldap:1.1.8
+          image: osixia/openldap:1.1.9
           volumeMounts:
           volumeMounts:
             - name: ldap-data
             - name: ldap-data
               mountPath: /var/lib/ldap
               mountPath: /var/lib/ldap
@@ -41,6 +41,8 @@ spec:
               value: "readonly"
               value: "readonly"
             - name: LDAP_READONLY_USER_PASSWORD
             - name: LDAP_READONLY_USER_PASSWORD
               value: "readonly"
               value: "readonly"
+            - name: LDAP_RFC2307BIS_SCHEMA
+              value: "false"
             - name: LDAP_BACKEND
             - name: LDAP_BACKEND
               value: "hdb"
               value: "hdb"
             - name: LDAP_TLS
             - name: LDAP_TLS
@@ -65,6 +67,8 @@ spec:
               value: "binddn=\"cn=admin,$LDAP_BASE_DN\" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase=\"$LDAP_BASE_DN\" type=refreshAndPersist interval=00:00:00:10 retry=\"60 +\" timeout=1 starttls=critical"
               value: "binddn=\"cn=admin,$LDAP_BASE_DN\" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase=\"$LDAP_BASE_DN\" type=refreshAndPersist interval=00:00:00:10 retry=\"60 +\" timeout=1 starttls=critical"
             - name: LDAP_REPLICATION_HOSTS
             - name: LDAP_REPLICATION_HOSTS
               value: "#PYTHON2BASH:['ldap://ldap-one-service', 'ldap://ldap-two-service']"
               value: "#PYTHON2BASH:['ldap://ldap-one-service', 'ldap://ldap-two-service']"
+            - name: KEEP_EXISTING_CONFIG
+              value: "false"
             - name: LDAP_REMOVE_CONFIG_AFTER_SETUP
             - name: LDAP_REMOVE_CONFIG_AFTER_SETUP
               value: "true"
               value: "true"
             - name: LDAP_SSL_HELPER_PREFIX
             - name: LDAP_SSL_HELPER_PREFIX

+ 8 - 0
example/kubernetes/using-secrets/environment/my-env.startup.yaml

@@ -18,6 +18,8 @@ LDAP_READONLY_USER: false
 LDAP_READONLY_USER_USERNAME: readonly
 LDAP_READONLY_USER_USERNAME: readonly
 LDAP_READONLY_USER_PASSWORD: readonly
 LDAP_READONLY_USER_PASSWORD: readonly
 
 
+LDAP_RFC2307BIS_SCHEMA: false
+
 # Backend
 # Backend
 LDAP_BACKEND: hdb
 LDAP_BACKEND: hdb
 
 
@@ -46,6 +48,12 @@ LDAP_REPLICATION_HOSTS:
   - ldap://ldap2.example.org
   - ldap://ldap2.example.org
 
 
 
 
+# Do not change the ldap config
+# - If set to true with an existing database, config will remain unchanged. Image tls and replication config will not be run.
+#   The container can be started with LDAP_ADMIN_PASSWORD and LDAP_CONFIG_PASSWORD empty or filled with fake data.
+# - If set to true when bootstrapping a new database, bootstap ldif and schema will not be added and tls and replication config will not be run.
+KEEP_EXISTING_CONFIG: false
+
 # Remove config after setup
 # Remove config after setup
 LDAP_REMOVE_CONFIG_AFTER_SETUP: true
 LDAP_REMOVE_CONFIG_AFTER_SETUP: true
 
 

+ 1 - 1
example/kubernetes/using-secrets/ldap-deployment.yaml

@@ -13,7 +13,7 @@ spec:
     spec:
     spec:
       containers:
       containers:
         - name: ldap
         - name: ldap
-          image: osixia/openldap:1.1.8
+          image: osixia/openldap:1.1.9
           args: ["--copy-service"]
           args: ["--copy-service"]
           volumeMounts:
           volumeMounts:
             - name: ldap-data
             - name: ldap-data

+ 8 - 2
image/Dockerfile

@@ -1,6 +1,6 @@
 # Use osixia/light-baseimage
 # Use osixia/light-baseimage
 # sources: https://github.com/osixia/docker-light-baseimage
 # sources: https://github.com/osixia/docker-light-baseimage
-FROM osixia/light-baseimage:0.2.6
+FROM osixia/light-baseimage:1.1.0
 MAINTAINER Bertrand Gouny <[email protected]>
 MAINTAINER Bertrand Gouny <[email protected]>
 
 
 # Add openldap user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
 # Add openldap user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
@@ -11,8 +11,14 @@ RUN groupadd -r openldap && useradd -r -g openldap openldap
 #          https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/:ssl-tools/download.sh
 #          https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/:ssl-tools/download.sh
 RUN apt-get -y update \
 RUN apt-get -y update \
     && /container/tool/add-service-available :ssl-tools \
     && /container/tool/add-service-available :ssl-tools \
-	  && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes --no-install-recommends \
+	  && LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
        ldap-utils \
        ldap-utils \
+       libsasl2-modules \
+       libsasl2-modules-db \
+       libsasl2-modules-gssapi-mit \
+       libsasl2-modules-ldap \
+       libsasl2-modules-otp \
+       libsasl2-modules-sql \
        openssl \
        openssl \
        slapd \
        slapd \
     && apt-get clean \
     && apt-get clean \

+ 7 - 0
image/environment/default.startup.yaml

@@ -18,6 +18,8 @@ LDAP_READONLY_USER: false
 LDAP_READONLY_USER_USERNAME: readonly
 LDAP_READONLY_USER_USERNAME: readonly
 LDAP_READONLY_USER_PASSWORD: readonly
 LDAP_READONLY_USER_PASSWORD: readonly
 
 
+LDAP_RFC2307BIS_SCHEMA: false
+
 # Backend
 # Backend
 LDAP_BACKEND: hdb
 LDAP_BACKEND: hdb
 
 
@@ -45,6 +47,11 @@ LDAP_REPLICATION_HOSTS:
   - ldap://ldap.example.org # The order must be the same on all ldap servers
   - ldap://ldap.example.org # The order must be the same on all ldap servers
   - ldap://ldap2.example.org
   - ldap://ldap2.example.org
 
 
+# Do not change the ldap config
+# - If set to true with an existing database, config will remain unchanged. Image tls and replication config will not be run.
+#   The container can be started with LDAP_ADMIN_PASSWORD and LDAP_CONFIG_PASSWORD empty or filled with fake data.
+# - If set to true when bootstrapping a new database, bootstap ldif and schema will not be added and tls and replication config will not be run.
+KEEP_EXISTING_CONFIG: false
 
 
 # Remove config after setup
 # Remove config after setup
 LDAP_REMOVE_CONFIG_AFTER_SETUP: true
 LDAP_REMOVE_CONFIG_AFTER_SETUP: true

+ 9 - 0
image/service/slapd/assets/config/bootstrap/ldif/custom/README.md

@@ -0,0 +1,9 @@
+Add your custom ldif files here if you don't want to overwrite image default boostrap ldif.
+at run time you can also mount a data volume with your ldif files to /container/service/slapd/assets/config/bootstrap/ldif/custom
+
+The startup script provide some substitution in bootstrap ldif files:
+`{{LDAP_BASE_DN }}` and `{{ LDAP_BACKEND }}` values are supported.
+Other `{{ * }}` substitution are left as is.
+
+Since startup script modifies `ldif` files,
+you **must** add `--copy-service` argument to entrypoint if you don't want to overwrite them.

+ 4 - 0
image/service/slapd/assets/config/bootstrap/schema/rfc2307bis.conf

@@ -0,0 +1,4 @@
+include         /etc/ldap/schema/core.schema
+include         /etc/ldap/schema/cosine.schema
+include         /etc/ldap/schema/inetorgperson.schema
+include         /etc/ldap/schema/rfc2307bis.schema

+ 158 - 0
image/service/slapd/assets/config/bootstrap/schema/rfc2307bis.ldif

@@ -0,0 +1,158 @@
+# AUTO-GENERATED FILE - DO NOT EDIT!! Use ldapmodify.
+# CRC32 6b6ad917
+dn: cn=rfc2307bis,cn=schema,cn=config
+objectClass: olcSchemaConfig
+cn: rfc2307bis
+olcAttributeTypes: {0}( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'The GECOS field;
+ the common name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE )
+olcAttributeTypes: {1}( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'The absol
+ ute path to the home directory' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4
+ .1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {2}( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'The path to
+ the login shell' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121
+ .1.26 SINGLE-VALUE )
+olcAttributeTypes: {3}( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' EQUALITY int
+ egerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.2
+ 7 SINGLE-VALUE )
+olcAttributeTypes: {4}( 1.3.6.1.1.1.1.6 NAME 'shadowMin' EQUALITY integerMat
+ ch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGL
+ E-VALUE )
+olcAttributeTypes: {5}( 1.3.6.1.1.1.1.7 NAME 'shadowMax' EQUALITY integerMat
+ ch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGL
+ E-VALUE )
+olcAttributeTypes: {6}( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' EQUALITY intege
+ rMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 S
+ INGLE-VALUE )
+olcAttributeTypes: {7}( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' EQUALITY integ
+ erMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+ SINGLE-VALUE )
+olcAttributeTypes: {8}( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' EQUALITY intege
+ rMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 S
+ INGLE-VALUE )
+olcAttributeTypes: {9}( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' EQUALITY integerM
+ atch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SIN
+ GLE-VALUE )
+olcAttributeTypes: {10}( 1.3.6.1.1.1.1.12 NAME 'memberUid' EQUALITY caseExac
+ tMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+olcAttributeTypes: {11}( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' EQUALITY
+ caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+olcAttributeTypes: {12}( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Net
+ group triple' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYN
+ TAX 1.3.6.1.4.1.1466.115.121.1.15 )
+olcAttributeTypes: {13}( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' DESC 'Service
+  port number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.
+ 3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {14}( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' DESC 'Ser
+ vice protocol name' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.12
+ 1.1.15 )
+olcAttributeTypes: {15}( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' DESC 'IP p
+ rotocol number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX
+ 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {16}( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' DESC 'ONC RPC
+ number' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.
+ 4.1.1466.115.121.1.27 SINGLE-VALUE )
+olcAttributeTypes: {17}( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'IPv4 add
+ resses as a dotted decimal omitting leading               zeros or IPv6 add
+ resses as defined in RFC2373' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.
+ 1.1466.115.121.1.26 )
+olcAttributeTypes: {18}( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'IP ne
+ twork omitting leading zeros, eg. 192.168' EQUALITY caseIgnoreIA5Match SYNT
+ AX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {19}( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'IP ne
+ tmask omitting leading zeros, eg. 255.255.255.0' EQUALITY caseIgnoreIA5Matc
+ h SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE )
+olcAttributeTypes: {20}( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'MAC addres
+ s in maximal, colon separated hex               notation, eg. 00:00:92:90:e
+ e:e2' EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {21}( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'rpc.boo
+ tparamd parameter' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.1
+ 21.1.26 )
+olcAttributeTypes: {22}( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Boot image n
+ ame' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+olcAttributeTypes: {23}( 1.3.6.1.1.1.1.26 NAME 'nisMapName' DESC 'Name of a
+ generic NIS map' EQUALITY caseIgnoreMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1
+ .15{64} )
+olcAttributeTypes: {24}( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' DESC 'A generic
+  NIS entry' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{10
+ 24} SINGLE-VALUE )
+olcAttributeTypes: {25}( 1.3.6.1.1.1.1.28 NAME 'nisPublicKey' DESC 'NIS publ
+ ic key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SING
+ LE-VALUE )
+olcAttributeTypes: {26}( 1.3.6.1.1.1.1.29 NAME 'nisSecretKey' DESC 'NIS secr
+ et key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SING
+ LE-VALUE )
+olcAttributeTypes: {27}( 1.3.6.1.1.1.1.30 NAME 'nisDomain' DESC 'NIS domain'
+  EQUALITY caseIgnoreIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+olcAttributeTypes: {28}( 1.3.6.1.1.1.1.31 NAME 'automountMapName' DESC 'auto
+ mount Map Name' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.1
+ 5 SINGLE-VALUE )
+olcAttributeTypes: {29}( 1.3.6.1.1.1.1.32 NAME 'automountKey' DESC 'Automoun
+ t Key value' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 S
+ INGLE-VALUE )
+olcAttributeTypes: {30}( 1.3.6.1.1.1.1.33 NAME 'automountInformation' DESC '
+ Automount information' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.
+ 121.1.15 SINGLE-VALUE )
+olcObjectClasses: {0}( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction
+  of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ u
+ idNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ ge
+ cos $ description ) )
+olcObjectClasses: {1}( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Additional
+  attributes for shadow passwords' SUP top AUXILIARY MUST uid MAY ( userPass
+ word $ description $ shadowLastChange $ shadowMin $ shadowMax $ shadowWarni
+ ng $ shadowInactive $ shadowExpire $ shadowFlag ) )
+olcObjectClasses: {2}( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction o
+ f a group of accounts' SUP top AUXILIARY MUST gidNumber MAY ( userPassword
+ $ memberUid $ description ) )
+olcObjectClasses: {3}( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Abstraction an
+  Internet Protocol service.               Maps an IP port and protocol (suc
+ h as tcp or udp)               to one or more names; the distinguished valu
+ e of               the cn attribute denotes the services canonical
+       name' SUP top STRUCTURAL MUST ( cn $ ipServicePort $ ipServiceProtoco
+ l ) MAY description )
+olcObjectClasses: {4}( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Abstraction o
+ f an IP protocol. Maps a protocol number               to one or more names
+ . The distinguished value of the cn               attribute denotes the pro
+ tocol canonical name' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber ) MAY
+  description )
+olcObjectClasses: {5}( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Abstraction of an
+  Open Network Computing (ONC)              [RFC1057] Remote Procedure Call
+ (RPC) binding.              This class maps an ONC RPC number to a name.
+            The distinguished value of the cn attribute denotes
+  the RPC service canonical name' SUP top STRUCTURAL MUST ( cn $ oncRpcNumbe
+ r ) MAY description )
+olcObjectClasses: {6}( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Abstraction of a
+ host, an IP device. The distinguished               value of the cn attribu
+ te denotes the hosts canonical            name. Device SHOULD be used as a
+ structural class' SUP top AUXILIARY MUST ( cn $ ipHostNumber ) MAY ( userPa
+ ssword $ l $ description $ manager ) )
+olcObjectClasses: {7}( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Abstraction of
+  a network. The distinguished value of               the cn attribute denot
+ es the network canonical name' SUP top STRUCTURAL MUST ipNetworkNumber MAY
+ ( cn $ ipNetmaskNumber $ l $ description $ manager ) )
+olcObjectClasses: {8}( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Abstraction
+ of a netgroup. May refer to other               netgroups' SUP top STRUCTUR
+ AL MUST cn MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
+olcObjectClasses: {9}( 1.3.6.1.1.1.2.9 NAME 'nisMap' DESC 'A generic abstrac
+ tion of a NIS map' SUP top STRUCTURAL MUST nisMapName MAY description )
+olcObjectClasses: {10}( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'An entry in
+ a NIS map' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) )
+olcObjectClasses: {11}( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'A device
+  with a MAC address; device SHOULD be               used as a structural cl
+ ass' SUP top AUXILIARY MAY macAddress )
+olcObjectClasses: {12}( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'A devic
+ e with boot parameters; device SHOULD be               used as a structural
+  class' SUP top AUXILIARY MAY ( bootFile $ bootParameter ) )
+olcObjectClasses: {13}( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' DESC 'An object
+  with a public and secret key' SUP top AUXILIARY MUST ( cn $ nisPublicKey $
+  nisSecretKey ) MAY ( uidNumber $ description ) )
+olcObjectClasses: {14}( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' DESC 'Associ
+ ates a NIS domain with a naming context' SUP top AUXILIARY MUST nisDomain )
+olcObjectClasses: {15}( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTU
+ RAL MUST automountMapName MAY description )
+olcObjectClasses: {16}( 1.3.6.1.1.1.2.17 NAME 'automount' DESC 'Automount in
+ formation' SUP top STRUCTURAL MUST ( automountKey $ automountInformation )
+ MAY description )
+olcObjectClasses: {17}( 1.3.6.1.1.1.2.18 NAME 'groupOfMembers' DESC 'A group
+  with members (DNs)' SUP top STRUCTURAL MUST cn MAY ( businessCategory $ se
+ eAlso $ owner $ ou $ o $ description $ member ) )

+ 385 - 0
image/service/slapd/assets/config/bootstrap/schema/rfc2307bis.schema

@@ -0,0 +1,385 @@
+#
+# rfc2307bis.schema
+#
+# Extracted from http://tools.ietf.org/id/draft-howard-rfc2307bis-02.txt
+# as of 2012/05/25, by Robin H. Johnson <[email protected]>
+# Found at http://dev.gentoo.org/~robbat2/distfiles/rfc2307bis.schema-20120525
+#
+# Changed so that OpenLDAP 2.4.39 is able to import the schema
+# on 2014/11/28 by Stijn Hoop <[email protected]>
+#
+#attributetype     ( 1.3.6.1.1.1.1.0 NAME 'uidNumber'
+#         DESC 'An integer uniquely identifying a user in an
+#               administrative domain'
+#         EQUALITY integerMatch
+#         ORDERING integerOrderingMatch
+#         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+#         SINGLE-VALUE )
+#
+#
+#attributetype     ( 1.3.6.1.1.1.1.1 NAME 'gidNumber'
+#         DESC 'An integer uniquely identifying a group in an
+#               administrative domain'
+#         EQUALITY integerMatch
+#         ORDERING integerOrderingMatch
+#         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+#         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.2 NAME 'gecos'
+         DESC 'The GECOS field; the common name'
+         EQUALITY caseIgnoreMatch
+         SUBSTR caseIgnoreSubstringsMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory'
+         DESC 'The absolute path to the home directory'
+         EQUALITY caseExactIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.4 NAME 'loginShell'
+         DESC 'The path to the login shell'
+         EQUALITY caseExactIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+         SINGLE-VALUE )
+
+attributetype     ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.6 NAME 'shadowMin'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.7 NAME 'shadowMax'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+
+
+attributetype     ( 1.3.6.1.1.1.1.12 NAME 'memberUid'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple'
+         DESC 'Netgroup triple'
+         EQUALITY caseIgnoreMatch
+         SUBSTR caseIgnoreSubstringsMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort'
+         DESC 'Service port number'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol'
+         DESC 'Service protocol name'
+         EQUALITY caseIgnoreMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber'
+         DESC 'IP protocol number'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber'
+         DESC 'ONC RPC number'
+         EQUALITY integerMatch
+         ORDERING integerOrderingMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
+         SINGLE-VALUE )
+
+
+
+
+
+
+
+
+attributetype     ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber'
+         DESC 'IPv4 addresses as a dotted decimal omitting leading
+               zeros or IPv6 addresses as defined in RFC2373'
+         EQUALITY caseIgnoreIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber'
+         DESC 'IP network omitting leading zeros, eg. 192.168'
+         EQUALITY caseIgnoreIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber'
+         DESC 'IP netmask omitting leading zeros, eg. 255.255.255.0'
+         EQUALITY caseIgnoreIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.22 NAME 'macAddress'
+         DESC 'MAC address in maximal, colon separated hex
+               notation, eg. 00:00:92:90:ee:e2'
+         EQUALITY caseIgnoreIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.23 NAME 'bootParameter'
+         DESC 'rpc.bootparamd parameter'
+         EQUALITY caseExactIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.24 NAME 'bootFile'
+         DESC 'Boot image name'
+         EQUALITY caseExactIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
+
+
+attributetype     ( 1.3.6.1.1.1.1.26 NAME 'nisMapName'
+         DESC 'Name of a generic NIS map'
+         EQUALITY caseIgnoreMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{64} )
+
+
+
+
+
+
+
+
+
+attributetype     ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry'
+         DESC 'A generic NIS entry'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{1024}
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.28 NAME 'nisPublicKey'
+         DESC 'NIS public key'
+         EQUALITY octetStringMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.29 NAME 'nisSecretKey'
+         DESC 'NIS secret key'
+         EQUALITY octetStringMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.30 NAME 'nisDomain'
+         DESC 'NIS domain'
+         EQUALITY caseIgnoreIA5Match
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{256} )
+
+
+attributetype     ( 1.3.6.1.1.1.1.31 NAME 'automountMapName'
+         DESC 'automount Map Name'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.32 NAME 'automountKey'
+         DESC 'Automount Key value'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+         SINGLE-VALUE )
+
+
+attributetype     ( 1.3.6.1.1.1.1.33 NAME 'automountInformation'
+         DESC 'Automount information'
+         EQUALITY caseExactMatch
+         SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
+         SINGLE-VALUE )
+
+
+
+objectclass     ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' SUP top AUXILIARY
+         DESC 'Abstraction of an account with POSIX attributes'
+         MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory )
+         MAY ( userPassword $ loginShell $ gecos $
+               description ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' SUP top AUXILIARY
+         DESC 'Additional attributes for shadow passwords'
+         MUST uid
+         MAY ( userPassword $ description $
+               shadowLastChange $ shadowMin $ shadowMax $
+               shadowWarning $ shadowInactive $
+               shadowExpire $ shadowFlag ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' SUP top AUXILIARY
+         DESC 'Abstraction of a group of accounts'
+         MUST gidNumber
+         MAY ( userPassword $ memberUid $
+               description ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.3 NAME 'ipService' SUP top STRUCTURAL
+         DESC 'Abstraction an Internet Protocol service.
+               Maps an IP port and protocol (such as tcp or udp)
+               to one or more names; the distinguished value of
+               the cn attribute denotes the services canonical
+               name'
+         MUST ( cn $ ipServicePort $ ipServiceProtocol )
+         MAY description )
+
+
+objectclass     ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' SUP top STRUCTURAL
+         DESC 'Abstraction of an IP protocol. Maps a protocol number
+               to one or more names. The distinguished value of the cn
+               attribute denotes the protocol canonical name'
+         MUST ( cn $ ipProtocolNumber )
+         MAY description )
+
+
+
+
+
+objectclass     ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' SUP top STRUCTURAL
+         DESC 'Abstraction of an Open Network Computing (ONC)
+              [RFC1057] Remote Procedure Call (RPC) binding.
+              This class maps an ONC RPC number to a name.
+              The distinguished value of the cn attribute denotes
+              the RPC service canonical name'
+         MUST ( cn $ oncRpcNumber )
+         MAY description )
+
+
+objectclass     ( 1.3.6.1.1.1.2.6 NAME 'ipHost' SUP top AUXILIARY
+         DESC 'Abstraction of a host, an IP device. The distinguished
+               value of the cn attribute denotes the hosts canonical
+            name. Device SHOULD be used as a structural class'
+         MUST ( cn $ ipHostNumber )
+         MAY ( userPassword $ l $ description $
+               manager ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' SUP top STRUCTURAL
+         DESC 'Abstraction of a network. The distinguished value of
+               the cn attribute denotes the network canonical name'
+         MUST ipNetworkNumber
+         MAY ( cn $ ipNetmaskNumber $ l $ description $ manager ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' SUP top STRUCTURAL
+         DESC 'Abstraction of a netgroup. May refer to other
+               netgroups'
+         MUST cn
+         MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.9 NAME 'nisMap' SUP top STRUCTURAL
+         DESC 'A generic abstraction of a NIS map'
+         MUST nisMapName
+         MAY description )
+
+
+objectclass     ( 1.3.6.1.1.1.2.10 NAME 'nisObject' SUP top STRUCTURAL
+         DESC 'An entry in a NIS map'
+         MUST ( cn $ nisMapEntry $ nisMapName ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' SUP top AUXILIARY
+         DESC 'A device with a MAC address; device SHOULD be
+               used as a structural class'
+         MAY macAddress )
+
+
+
+
+
+objectclass     ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' SUP top AUXILIARY
+         DESC 'A device with boot parameters; device SHOULD be
+               used as a structural class'
+         MAY ( bootFile $ bootParameter ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.14 NAME 'nisKeyObject' SUP top AUXILIARY
+         DESC 'An object with a public and secret key'
+         MUST ( cn $ nisPublicKey $ nisSecretKey )
+         MAY ( uidNumber $ description ) )
+
+
+objectclass     ( 1.3.6.1.1.1.2.15 NAME 'nisDomainObject' SUP top AUXILIARY
+         DESC 'Associates a NIS domain with a naming context'
+         MUST nisDomain )
+
+
+objectclass     ( 1.3.6.1.1.1.2.16 NAME 'automountMap' SUP top STRUCTURAL
+         MUST ( automountMapName )
+         MAY description )
+
+
+objectclass     ( 1.3.6.1.1.1.2.17 NAME 'automount' SUP top STRUCTURAL
+         DESC 'Automount information'
+         MUST ( automountKey $ automountInformation )
+         MAY description )
+
+
+objectclass     ( 1.3.6.1.1.1.2.18 NAME 'groupOfMembers' SUP top STRUCTURAL
+         DESC 'A group with members (DNs)'
+         MUST cn
+         MAY ( businessCategory $ seeAlso $ owner $ ou $ o $
+               description $ member ) )

+ 12 - 1
image/service/slapd/assets/schema-to-ldif.sh

@@ -11,9 +11,15 @@ pushd ${tmpd} >>/dev/null
 
 
 echo "include /etc/ldap/schema/core.schema" >> convert.dat
 echo "include /etc/ldap/schema/core.schema" >> convert.dat
 echo "include /etc/ldap/schema/cosine.schema" >> convert.dat
 echo "include /etc/ldap/schema/cosine.schema" >> convert.dat
-echo "include /etc/ldap/schema/nis.schema" >> convert.dat
 echo "include /etc/ldap/schema/inetorgperson.schema" >> convert.dat
 echo "include /etc/ldap/schema/inetorgperson.schema" >> convert.dat
 
 
+if [ -e "/etc/ldap/schema/rfc2307bis.schema" ]; then
+  echo "include /etc/ldap/schema/rfc2307bis.schema" >> convert.dat
+else
+  echo "include /etc/ldap/schema/nis.schema" >> convert.dat
+fi
+
+
 for schema in ${SCHEMAS} ; do
 for schema in ${SCHEMAS} ; do
     echo "include ${schema}" >> convert.dat
     echo "include ${schema}" >> convert.dat
 done
 done
@@ -31,6 +37,11 @@ for schema in ${SCHEMAS} ; do
     schema_dir=`dirname ${fullpath}`
     schema_dir=`dirname ${fullpath}`
     ldif_file=${schema_name}.ldif
     ldif_file=${schema_name}.ldif
 
 
+    if [ -e "${schema_dir}/${ldif_file}" ]; then
+      log-helper warning "${schema} ldif file ${schema_dir}/${ldif_file} already exists skipping conversion"
+      continue
+    fi
+
     find . -name *\}${schema_name}.ldif -exec mv '{}' ./${ldif_file} \;
     find . -name *\}${schema_name}.ldif -exec mv '{}' ./${ldif_file} \;
 
 
     # TODO: these sed invocations could all be combined
     # TODO: these sed invocations could all be combined

+ 246 - 205
image/service/slapd/startup.sh

@@ -24,6 +24,12 @@ WAS_STARTED_WITH_TLS="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls"
 WAS_STARTED_WITH_TLS_ENFORCE="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls-enforce"
 WAS_STARTED_WITH_TLS_ENFORCE="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls-enforce"
 WAS_STARTED_WITH_REPLICATION="/etc/ldap/slapd.d/docker-openldap-was-started-with-replication"
 WAS_STARTED_WITH_REPLICATION="/etc/ldap/slapd.d/docker-openldap-was-started-with-replication"
 
 
+LDAP_TLS_CA_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
+LDAP_TLS_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
+LDAP_TLS_KEY_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_KEY_FILENAME"
+LDAP_TLS_DH_PARAM_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/dhparam.pem"
+
+
 # CONTAINER_SERVICE_DIR and CONTAINER_STATE_DIR variables are set by
 # CONTAINER_SERVICE_DIR and CONTAINER_STATE_DIR variables are set by
 # the baseimage run tool more info : https://github.com/osixia/docker-light-baseimage
 # the baseimage run tool more info : https://github.com/osixia/docker-light-baseimage
 
 
@@ -56,6 +62,17 @@ if [ ! -e "$FIRST_START_DONE" ]; then
     fi
     fi
   }
   }
 
 
+  function ldap_add_or_modify (){
+    local LDIF_FILE=$1
+    sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" $LDIF_FILE
+    sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" $LDIF_FILE
+    if grep -iq changetype $LDIF_FILE ; then
+        ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $LDIF_FILE 2>&1 | log-helper debug || ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f $LDIF_FILE 2>&1 | log-helper debug
+    else
+        ldapadd -Y EXTERNAL -Q -H ldapi:/// -f $LDIF_FILE |& log-helper debug
+    fi
+  }
+
   #
   #
   # Global variables
   # Global variables
   #
   #
@@ -71,7 +88,6 @@ if [ ! -e "$FIRST_START_DONE" ]; then
     log-helper info "Database and config directory are empty..."
     log-helper info "Database and config directory are empty..."
     log-helper info "Init new ldap server..."
     log-helper info "Init new ldap server..."
 
 
-
     cat <<EOF | debconf-set-selections
     cat <<EOF | debconf-set-selections
 slapd slapd/internal/generated_adminpw password ${LDAP_ADMIN_PASSWORD}
 slapd slapd/internal/generated_adminpw password ${LDAP_ADMIN_PASSWORD}
 slapd slapd/internal/adminpw password ${LDAP_ADMIN_PASSWORD}
 slapd slapd/internal/adminpw password ${LDAP_ADMIN_PASSWORD}
@@ -90,6 +106,24 @@ EOF
 
 
     dpkg-reconfigure -f noninteractive slapd
     dpkg-reconfigure -f noninteractive slapd
 
 
+    # RFC2307bis schema
+    if [ "${LDAP_RFC2307BIS_SCHEMA,,}" == "true" ]; then
+
+      log-helper info "Switching schema to RFC2307bis..."
+      cp ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema/rfc2307bis.* /etc/ldap/schema/
+
+      rm -f /etc/ldap/slapd.d/cn=config/cn=schema/*
+
+      mkdir -p /tmp/schema
+      slaptest -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema/rfc2307bis.conf -F /tmp/schema
+      mv /tmp/schema/cn=config/cn=schema/* /etc/ldap/slapd.d/cn=config/cn=schema
+      rm -r /tmp/schema
+
+      chown -R openldap:openldap /etc/ldap/slapd.d/cn=config/cn=schema
+    fi
+
+    rm ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema/rfc2307bis.*
+
   #
   #
   # Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)
   # Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)
   #
   #
@@ -105,275 +139,282 @@ EOF
     exit 1
     exit 1
   fi
   fi
 
 
-  #
-  # start OpenLDAP
-  #
-
-  # get previous hostname if OpenLDAP was started with replication
-  # to avoid configuration pbs
-  PREVIOUS_HOSTNAME_PARAM=""
-  if [ -e "$WAS_STARTED_WITH_REPLICATION" ]; then
+  if [ "${KEEP_EXISTING_CONFIG,,}" == "true" ]; then
+    log-helper info "/!\ KEEP_EXISTING_CONFIG = true configration will not be updated"
+  else
+    #
+    # start OpenLDAP
+    #
+
+    # get previous hostname if OpenLDAP was started with replication
+    # to avoid configuration pbs
+    PREVIOUS_HOSTNAME_PARAM=""
+    if [ -e "$WAS_STARTED_WITH_REPLICATION" ]; then
+
+      source $WAS_STARTED_WITH_REPLICATION
+
+      # if previous hostname != current hostname
+      # set previous hostname to a loopback ip in /etc/hosts
+      if [ "$PREVIOUS_HOSTNAME" != "$HOSTNAME" ]; then
+        echo "127.0.0.2 $PREVIOUS_HOSTNAME" >> /etc/hosts
+        PREVIOUS_HOSTNAME_PARAM="ldap://$PREVIOUS_HOSTNAME"
+      fi
+    fi
 
 
-    source $WAS_STARTED_WITH_REPLICATION
+    # if the config was bootstraped with TLS
+    # to avoid error (#6) (#36) and (#44)
+    # we create fake temporary certificates if they do not exists
+    if [ -e "$WAS_STARTED_WITH_TLS" ]; then
+      source $WAS_STARTED_WITH_TLS
 
 
-    # if previous hostname != current hostname
-    # set previous hostname to a loopback ip in /etc/hosts
-    if [ "$PREVIOUS_HOSTNAME" != "$HOSTNAME" ]; then
-      echo "127.0.0.2 $PREVIOUS_HOSTNAME" >> /etc/hosts
-      PREVIOUS_HOSTNAME_PARAM="ldap://$PREVIOUS_HOSTNAME"
-    fi
-  fi
+      log-helper debug "Check previous TLS certificates..."
 
 
-  # if the config was bootstraped with TLS
-  # to avoid error (#6) (#36) and (#44)
-  # we create fake temporary certificates if they do not exists
-  if [ -e "$WAS_STARTED_WITH_TLS" ]; then
-    source $WAS_STARTED_WITH_TLS
+      # fix for #73
+      # image started with an existing database/config created before 1.1.5
+      [[ -z "$PREVIOUS_LDAP_TLS_CA_CRT_PATH" ]] && PREVIOUS_LDAP_TLS_CA_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
+      [[ -z "$PREVIOUS_LDAP_TLS_CRT_PATH" ]] && PREVIOUS_LDAP_TLS_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
+      [[ -z "$PREVIOUS_LDAP_TLS_KEY_PATH" ]] && PREVIOUS_LDAP_TLS_KEY_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_KEY_FILENAME"
+      [[ -z "$PREVIOUS_LDAP_TLS_DH_PARAM_PATH" ]] && PREVIOUS_LDAP_TLS_DH_PARAM_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/dhparam.pem"
 
 
-    log-helper debug "Check previous TLS certificates..."
+      ssl-helper $LDAP_SSL_HELPER_PREFIX $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_CA_CRT_PATH
+      [ -f ${PREVIOUS_LDAP_TLS_DH_PARAM_PATH} ] || openssl dhparam -out ${LDAP_TLS_DH_PARAM_PATH} 2048
 
 
-    # fix for #73
-    # image started with an existing database/config created before 1.1.5
-    [[ -z "$PREVIOUS_LDAP_TLS_CA_CRT_PATH" ]] && PREVIOUS_LDAP_TLS_CA_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
-    [[ -z "$PREVIOUS_LDAP_TLS_CRT_PATH" ]] && PREVIOUS_LDAP_TLS_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
-    [[ -z "$PREVIOUS_LDAP_TLS_KEY_PATH" ]] && PREVIOUS_LDAP_TLS_KEY_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_KEY_FILENAME"
-    [[ -z "$PREVIOUS_LDAP_TLS_DH_PARAM_PATH" ]] && PREVIOUS_LDAP_TLS_DH_PARAM_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/dhparam.pem"
+      chmod 600 ${PREVIOUS_LDAP_TLS_DH_PARAM_PATH}
+      chown openldap:openldap $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_CA_CRT_PATH $PREVIOUS_LDAP_TLS_DH_PARAM_PATH
+    fi
 
 
-    ssl-helper $LDAP_SSL_HELPER_PREFIX $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_CA_CRT_PATH
-    [ -f ${PREVIOUS_LDAP_TLS_DH_PARAM_PATH} ] || openssl dhparam -out ${LDAP_TLS_DH_PARAM_PATH} 2048
+    # start OpenLDAP
+    log-helper info "Start OpenLDAP..."
 
 
-    chmod 600 ${PREVIOUS_LDAP_TLS_DH_PARAM_PATH}
-    chown openldap:openldap $PREVIOUS_LDAP_TLS_CRT_PATH $PREVIOUS_LDAP_TLS_KEY_PATH $PREVIOUS_LDAP_TLS_CA_CRT_PATH $PREVIOUS_LDAP_TLS_DH_PARAM_PATH
-  fi
+    if log-helper level ge debug; then
+      slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME_PARAM ldap://localhost ldapi:///" -u openldap -g openldap -d $LDAP_LOG_LEVEL 2>&1 &
+    else
+      slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME_PARAM ldap://localhost ldapi:///" -u openldap -g openldap
+    fi
 
 
-  # start OpenLDAP
-  log-helper info "Start OpenLDAP..."
 
 
-  if log-helper level eq debug; then
-    # debug
-    slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME_PARAM ldap://localhost ldapi:///" -u openldap -g openldap -d $LDAP_LOG_LEVEL 2>&1 &
-  else
-    slapd -h "ldap://$HOSTNAME $PREVIOUS_HOSTNAME_PARAM ldap://localhost ldapi:///" -u openldap -g openldap
-  fi
+    log-helper info "Waiting for OpenLDAP to start..."
+    while [ ! -e /run/slapd/slapd.pid ]; do sleep 0.1; done
 
 
+    #
+    # setup bootstrap config - Part 2
+    #
+    if $BOOTSTRAP; then
 
 
-  log-helper info "Waiting for OpenLDAP to start..."
-  while [ ! -e /run/slapd/slapd.pid ]; do sleep 0.1; done
+      log-helper info "Add bootstrap schemas..."
 
 
-  #
-  # setup bootstrap config - Part 2
-  #
-  if $BOOTSTRAP; then
-
-    log-helper info "Add bootstrap schemas..."
-
-    # add ppolicy schema
-    ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif 2>&1 | log-helper debug
-
-    # convert schemas to ldif
-    SCHEMAS=""
-    for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.schema -type f); do
-      SCHEMAS="$SCHEMAS ${f}"
-    done
-    ${CONTAINER_SERVICE_DIR}/slapd/assets/schema-to-ldif.sh "$SCHEMAS"
-
-    # add converted schemas
-    for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.ldif -type f); do
-      log-helper debug "Processing file ${f}"
-      # add schema if not already exists
-      SCHEMA=$(basename "${f}" .ldif)
-      ADD_SCHEMA=$(is_new_schema $SCHEMA)
-      if [ "$ADD_SCHEMA" -eq 1 ]; then
-        ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f 2>&1 | log-helper debug
-      else
-        log-helper info "schema ${f} already exists"
-      fi
-    done
+      # add ppolicy schema
+      ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif 2>&1 | log-helper debug
 
 
-    # set config password
-    LDAP_CONFIG_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_CONFIG_PASSWORD)
-    sed -i "s|{{ LDAP_CONFIG_PASSWORD_ENCRYPTED }}|${LDAP_CONFIG_PASSWORD_ENCRYPTED}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/01-config-password.ldif
+      # convert schemas to ldif
+      SCHEMAS=""
+      for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.schema -type f); do
+        SCHEMAS="$SCHEMAS ${f}"
+      done
+      ${CONTAINER_SERVICE_DIR}/slapd/assets/schema-to-ldif.sh "$SCHEMAS"
+
+      # add converted schemas
+      for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/schema -name \*.ldif -type f); do
+        log-helper debug "Processing file ${f}"
+        # add schema if not already exists
+        SCHEMA=$(basename "${f}" .ldif)
+        ADD_SCHEMA=$(is_new_schema $SCHEMA)
+        if [ "$ADD_SCHEMA" -eq 1 ]; then
+          ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f 2>&1 | log-helper debug
+        else
+          log-helper info "schema ${f} already exists"
+        fi
+      done
 
 
-    # adapt security config file
-    get_ldap_base_dn
-    sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/02-security.ldif
+      # set config password
+      LDAP_CONFIG_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_CONFIG_PASSWORD)
+      sed -i "s|{{ LDAP_CONFIG_PASSWORD_ENCRYPTED }}|${LDAP_CONFIG_PASSWORD_ENCRYPTED}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/01-config-password.ldif
 
 
-    # process config files (*.ldif) in bootstrap directory (do no process files in subdirectories)
-    log-helper info "Add bootstrap ldif..."
-    for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif -mindepth 1 -maxdepth 1 -type f -name \*.ldif  | sort); do
-      log-helper debug "Processing file ${f}"
-      sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" $f
-      sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" $f
-      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $f 2>&1 | log-helper debug || ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f $f 2>&1 | log-helper debug
-    done
+      # adapt security config file
+      get_ldap_base_dn
+      sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/02-security.ldif
 
 
-    # read only user
-    if [ "${LDAP_READONLY_USER,,}" == "true" ]; then
+      # process config files (*.ldif) in bootstrap directory (do no process files in subdirectories)
+      log-helper info "Add image bootstrap ldif..."
+      for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif -mindepth 1 -maxdepth 1 -type f -name \*.ldif  | sort); do
+        log-helper debug "Processing file ${f}"
+        ldap_add_or_modify "$f"
+      done
 
 
-      log-helper info "Add read only user..."
+      log-helper info "Add custom bootstrap ldif..."
+      for f in $(find ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/custom -type f -name \*.ldif  | sort); do
+        log-helper debug "Processing file ${f}"
+        ldap_add_or_modify "$f"
+      done
 
 
-      LDAP_READONLY_USER_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_READONLY_USER_PASSWORD)
-      sed -i "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
-      sed -i "s|{{ LDAP_READONLY_USER_PASSWORD_ENCRYPTED }}|${LDAP_READONLY_USER_PASSWORD_ENCRYPTED}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
-      sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
+      # read only user
+      if [ "${LDAP_READONLY_USER,,}" == "true" ]; then
 
 
-      sed -i "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
-      sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
+        log-helper info "Add read only user..."
 
 
-      sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
+        LDAP_READONLY_USER_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_READONLY_USER_PASSWORD)
+        sed -i "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
+        sed -i "s|{{ LDAP_READONLY_USER_PASSWORD_ENCRYPTED }}|${LDAP_READONLY_USER_PASSWORD_ENCRYPTED}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
+        sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif
 
 
-      log-helper debug "Processing file ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif"
-      ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif 2>&1 | log-helper debug
+        sed -i "s|{{ LDAP_READONLY_USER_USERNAME }}|${LDAP_READONLY_USER_USERNAME}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
+        sed -i "s|{{ LDAP_BASE_DN }}|${LDAP_BASE_DN}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
 
 
-      log-helper debug "Processing file ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif"
-      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif 2>&1 | log-helper debug
+        sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif
 
 
-    fi
-  fi
+        log-helper debug "Processing file ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif"
+        ldapmodify -h localhost -p 389 -D cn=admin,$LDAP_BASE_DN -w $LDAP_ADMIN_PASSWORD -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user.ldif 2>&1 | log-helper debug
 
 
-  #
-  # TLS config
-  #
-  if [ -e "$WAS_STARTED_WITH_TLS" ] && [ "${LDAP_TLS,,}" != "true" ]; then
-    log-helper error "/!\ WARNING: LDAP_TLS=false but the container was previously started with LDAP_TLS=true"
-    log-helper error "TLS can't be disabled once added. Ignoring LDAP_TLS=false."
-    LDAP_TLS=true
-  fi
+        log-helper debug "Processing file ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif"
+        ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/bootstrap/ldif/readonly-user/readonly-user-acl.ldif 2>&1 | log-helper debug
 
 
-  if [ -e "$WAS_STARTED_WITH_TLS_ENFORCE" ] && [ "${LDAP_TLS_ENFORCE,,}" != "true" ]; then
-    log-helper error "/!\ WARNING: LDAP_TLS_ENFORCE=false but the container was previously started with LDAP_TLS_ENFORCE=true"
-    log-helper error "TLS enforcing can't be disabled once added. Ignoring LDAP_TLS_ENFORCE=false."
-    LDAP_TLS_ENFORCE=true
-  fi
+      fi
+    fi
 
 
-  if [ "${LDAP_TLS,,}" == "true" ]; then
+    #
+    # TLS config
+    #
+    if [ -e "$WAS_STARTED_WITH_TLS" ] && [ "${LDAP_TLS,,}" != "true" ]; then
+      log-helper error "/!\ WARNING: LDAP_TLS=false but the container was previously started with LDAP_TLS=true"
+      log-helper error "TLS can't be disabled once added. Ignoring LDAP_TLS=false."
+      LDAP_TLS=true
+    fi
 
 
-    log-helper info "Add TLS config..."
+    if [ -e "$WAS_STARTED_WITH_TLS_ENFORCE" ] && [ "${LDAP_TLS_ENFORCE,,}" != "true" ]; then
+      log-helper error "/!\ WARNING: LDAP_TLS_ENFORCE=false but the container was previously started with LDAP_TLS_ENFORCE=true"
+      log-helper error "TLS enforcing can't be disabled once added. Ignoring LDAP_TLS_ENFORCE=false."
+      LDAP_TLS_ENFORCE=true
+    fi
 
 
-    LDAP_TLS_CA_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CA_CRT_FILENAME"
-    LDAP_TLS_CRT_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_CRT_FILENAME"
-    LDAP_TLS_KEY_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/$LDAP_TLS_KEY_FILENAME"
-    LDAP_TLS_DH_PARAM_PATH="${CONTAINER_SERVICE_DIR}/slapd/assets/certs/dhparam.pem"
+    if [ "${LDAP_TLS,,}" == "true" ]; then
 
 
-    # generate a certificate and key with ssl-helper tool if LDAP_CRT and LDAP_KEY files don't exists
-    # https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/:ssl-tools/assets/tool/ssl-helper
-    ssl-helper $LDAP_SSL_HELPER_PREFIX $LDAP_TLS_CRT_PATH $LDAP_TLS_KEY_PATH $LDAP_TLS_CA_CRT_PATH
+      log-helper info "Add TLS config..."
 
 
-    # create DHParamFile if not found
-    [ -f ${LDAP_TLS_DH_PARAM_PATH} ] || openssl dhparam -out ${LDAP_TLS_DH_PARAM_PATH} 2048
-    chmod 600 ${LDAP_TLS_DH_PARAM_PATH}
+      # generate a certificate and key with ssl-helper tool if LDAP_CRT and LDAP_KEY files don't exists
+      # https://github.com/osixia/docker-light-baseimage/blob/stable/image/service-available/:ssl-tools/assets/tool/ssl-helper
+      ssl-helper $LDAP_SSL_HELPER_PREFIX $LDAP_TLS_CRT_PATH $LDAP_TLS_KEY_PATH $LDAP_TLS_CA_CRT_PATH
 
 
-    # fix file permissions
-    chown -R openldap:openldap ${CONTAINER_SERVICE_DIR}/slapd
+      # create DHParamFile if not found
+      [ -f ${LDAP_TLS_DH_PARAM_PATH} ] || openssl dhparam -out ${LDAP_TLS_DH_PARAM_PATH} 2048
+      chmod 600 ${LDAP_TLS_DH_PARAM_PATH}
 
 
-    # adapt tls ldif
-    sed -i "s|{{ LDAP_TLS_CA_CRT_PATH }}|${LDAP_TLS_CA_CRT_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
-    sed -i "s|{{ LDAP_TLS_CRT_PATH }}|${LDAP_TLS_CRT_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
-    sed -i "s|{{ LDAP_TLS_KEY_PATH }}|${LDAP_TLS_KEY_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
-    sed -i "s|{{ LDAP_TLS_DH_PARAM_PATH }}|${LDAP_TLS_DH_PARAM_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      # fix file permissions
+      chown -R openldap:openldap ${CONTAINER_SERVICE_DIR}/slapd
 
 
-    sed -i "s|{{ LDAP_TLS_CIPHER_SUITE }}|${LDAP_TLS_CIPHER_SUITE}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
-    sed -i "s|{{ LDAP_TLS_VERIFY_CLIENT }}|${LDAP_TLS_VERIFY_CLIENT}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      # adapt tls ldif
+      sed -i "s|{{ LDAP_TLS_CA_CRT_PATH }}|${LDAP_TLS_CA_CRT_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      sed -i "s|{{ LDAP_TLS_CRT_PATH }}|${LDAP_TLS_CRT_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      sed -i "s|{{ LDAP_TLS_KEY_PATH }}|${LDAP_TLS_KEY_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      sed -i "s|{{ LDAP_TLS_DH_PARAM_PATH }}|${LDAP_TLS_DH_PARAM_PATH}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
 
 
-    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif 2>&1 | log-helper debug
+      sed -i "s|{{ LDAP_TLS_CIPHER_SUITE }}|${LDAP_TLS_CIPHER_SUITE}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
+      sed -i "s|{{ LDAP_TLS_VERIFY_CLIENT }}|${LDAP_TLS_VERIFY_CLIENT}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif
 
 
-    [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
-    echo "export PREVIOUS_LDAP_TLS_CA_CRT_PATH=${LDAP_TLS_CA_CRT_PATH}" > $WAS_STARTED_WITH_TLS
-    echo "export PREVIOUS_LDAP_TLS_CRT_PATH=${LDAP_TLS_CRT_PATH}" >> $WAS_STARTED_WITH_TLS
-    echo "export PREVIOUS_LDAP_TLS_KEY_PATH=${LDAP_TLS_KEY_PATH}" >> $WAS_STARTED_WITH_TLS
-    echo "export PREVIOUS_LDAP_TLS_DH_PARAM_PATH=${LDAP_TLS_DH_PARAM_PATH}" >> $WAS_STARTED_WITH_TLS
+      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enable.ldif 2>&1 | log-helper debug
 
 
-    # ldap client config
-    sed -i --follow-symlinks "s,TLS_CACERT.*,TLS_CACERT ${LDAP_TLS_CA_CRT_PATH},g" /etc/ldap/ldap.conf
-    echo "TLS_REQCERT ${LDAP_TLS_VERIFY_CLIENT}" >> /etc/ldap/ldap.conf
-    cp -f /etc/ldap/ldap.conf ${CONTAINER_SERVICE_DIR}/slapd/assets/ldap.conf
+      [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
+      echo "export PREVIOUS_LDAP_TLS_CA_CRT_PATH=${LDAP_TLS_CA_CRT_PATH}" > $WAS_STARTED_WITH_TLS
+      echo "export PREVIOUS_LDAP_TLS_CRT_PATH=${LDAP_TLS_CRT_PATH}" >> $WAS_STARTED_WITH_TLS
+      echo "export PREVIOUS_LDAP_TLS_KEY_PATH=${LDAP_TLS_KEY_PATH}" >> $WAS_STARTED_WITH_TLS
+      echo "export PREVIOUS_LDAP_TLS_DH_PARAM_PATH=${LDAP_TLS_DH_PARAM_PATH}" >> $WAS_STARTED_WITH_TLS
 
 
-    [[ -f "$HOME/.ldaprc" ]] && rm -f $HOME/.ldaprc
-    echo "TLS_CERT ${LDAP_TLS_CRT_PATH}" > $HOME/.ldaprc
-    echo "TLS_KEY ${LDAP_TLS_KEY_PATH}" >> $HOME/.ldaprc
-    cp -f $HOME/.ldaprc ${CONTAINER_SERVICE_DIR}/slapd/assets/.ldaprc
+      # enforce TLS
+      if [ "${LDAP_TLS_ENFORCE,,}" == "true" ]; then
+        log-helper info "Add enforce TLS..."
+        ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enforce-enable.ldif 2>&1 | log-helper debug
+        touch $WAS_STARTED_WITH_TLS_ENFORCE
 
 
-    # enforce TLS
-    if [ "${LDAP_TLS_ENFORCE,,}" == "true" ]; then
-      log-helper info "Add enforce TLS..."
-      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enforce-enable.ldif 2>&1 | log-helper debug
-      touch $WAS_STARTED_WITH_TLS_ENFORCE
+      # disable tls enforcing (not possible for now)
+      #else
+        #log-helper info "Disable enforce TLS..."
+        #ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enforce-disable.ldif 2>&1 | log-helper debug || true
+        #[[ -f "$WAS_STARTED_WITH_TLS_ENFORCE" ]] && rm -f "$WAS_STARTED_WITH_TLS_ENFORCE"
+      fi
 
 
-    # disable tls enforcing (not possible for now)
+    # disable tls (not possible for now)
     #else
     #else
-      #log-helper info "Disable enforce TLS..."
-      #ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-enforce-disable.ldif 2>&1 | log-helper debug || true
-      #[[ -f "$WAS_STARTED_WITH_TLS_ENFORCE" ]] && rm -f "$WAS_STARTED_WITH_TLS_ENFORCE"
+      #log-helper info "Disable TLS config..."
+      #ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-disable.ldif 2>&1 | log-helper debug || true
+      #[[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
     fi
     fi
 
 
-  # disable tls (not possible for now)
-  #else
-    #log-helper info "Disable TLS config..."
-    #ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/tls/tls-disable.ldif 2>&1 | log-helper debug || true
-    #[[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
-  fi
 
 
 
 
+    #
+    # Replication config
+    #
 
 
-  #
-  # Replication config
-  #
+    function disableReplication() {
+      sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif
+      ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif 2>&1 | log-helper debug || true
+      [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
+    }
 
 
-  function disableReplication() {
-    sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif
-    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-disable.ldif 2>&1 | log-helper debug || true
-    [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
-  }
+    if [ "${LDAP_REPLICATION,,}" == "true" ]; then
 
 
-  if [ "${LDAP_REPLICATION,,}" == "true" ]; then
+      log-helper info "Add replication config..."
+      disableReplication || true
 
 
-    log-helper info "Add replication config..."
-    disableReplication || true
+      i=1
+      for host in $(complex-bash-env iterate LDAP_REPLICATION_HOSTS)
+      do
+        sed -i "s|{{ LDAP_REPLICATION_HOSTS }}|olcServerID: $i ${!host}\n{{ LDAP_REPLICATION_HOSTS }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+        sed -i "s|{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|olcSyncRepl: rid=00$i provider=${!host} ${LDAP_REPLICATION_CONFIG_SYNCPROV}\n{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+        sed -i "s|{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}|olcSyncRepl: rid=10$i provider=${!host} ${LDAP_REPLICATION_DB_SYNCPROV}\n{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
 
 
-    i=1
-    for host in $(complex-bash-env iterate LDAP_REPLICATION_HOSTS)
-    do
-      sed -i "s|{{ LDAP_REPLICATION_HOSTS }}|olcServerID: $i ${!host}\n{{ LDAP_REPLICATION_HOSTS }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-      sed -i "s|{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|olcSyncRepl: rid=00$i provider=${!host} ${LDAP_REPLICATION_CONFIG_SYNCPROV}\n{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-      sed -i "s|{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}|olcSyncRepl: rid=10$i provider=${!host} ${LDAP_REPLICATION_DB_SYNCPROV}\n{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+        ((i++))
+      done
 
 
-      ((i++))
-    done
+      get_ldap_base_dn
+      sed -i "s|\$LDAP_BASE_DN|$LDAP_BASE_DN|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "s|\$LDAP_ADMIN_PASSWORD|$LDAP_ADMIN_PASSWORD|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "s|\$LDAP_CONFIG_PASSWORD|$LDAP_CONFIG_PASSWORD|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
 
 
-    get_ldap_base_dn
-    sed -i "s|\$LDAP_BASE_DN|$LDAP_BASE_DN|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-    sed -i "s|\$LDAP_ADMIN_PASSWORD|$LDAP_ADMIN_PASSWORD|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-    sed -i "s|\$LDAP_CONFIG_PASSWORD|$LDAP_CONFIG_PASSWORD|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "/{{ LDAP_REPLICATION_HOSTS }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "/{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "/{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
 
 
-    sed -i "/{{ LDAP_REPLICATION_HOSTS }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-    sed -i "/{{ LDAP_REPLICATION_HOSTS_CONFIG_SYNC_REPL }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
-    sed -i "/{{ LDAP_REPLICATION_HOSTS_DB_SYNC_REPL }}/d" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
 
 
-    sed -i "s|{{ LDAP_BACKEND }}|${LDAP_BACKEND}|g" ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif
+      ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif 2>&1 | log-helper debug || true
 
 
-    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f ${CONTAINER_SERVICE_DIR}/slapd/assets/config/replication/replication-enable.ldif 2>&1 | log-helper debug || true
+      [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
+      echo "export PREVIOUS_HOSTNAME=${HOSTNAME}" > $WAS_STARTED_WITH_REPLICATION
 
 
-    [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
-    echo "export PREVIOUS_HOSTNAME=${HOSTNAME}" > $WAS_STARTED_WITH_REPLICATION
+    else
 
 
-  else
+      log-helper info "Disable replication config..."
+      disableReplication || true
+
+    fi
 
 
-    log-helper info "Disable replication config..."
-    disableReplication || true
+    #
+    # stop OpenLDAP
+    #
+    log-helper info "Stop OpenLDAP..."
 
 
+    SLAPD_PID=$(cat /run/slapd/slapd.pid)
+    kill -15 $SLAPD_PID
+    while [ -e /proc/$SLAPD_PID ]; do sleep 0.1; done # wait until slapd is terminated
   fi
   fi
 
 
   #
   #
-  # stop OpenLDAP
+  # ldap client config
   #
   #
-  log-helper info "Stop OpenLDAP..."
+  if [ "${LDAP_TLS,,}" == "true" ]; then
+    log-helper info "Configure ldap client TLS configuration..."
+    sed -i --follow-symlinks "s,TLS_CACERT.*,TLS_CACERT ${LDAP_TLS_CA_CRT_PATH},g" /etc/ldap/ldap.conf
+    echo "TLS_REQCERT ${LDAP_TLS_VERIFY_CLIENT}" >> /etc/ldap/ldap.conf
+    cp -f /etc/ldap/ldap.conf ${CONTAINER_SERVICE_DIR}/slapd/assets/ldap.conf
 
 
-  SLAPD_PID=$(cat /run/slapd/slapd.pid)
-  kill -15 $SLAPD_PID
-  while [ -e /proc/$SLAPD_PID ]; do sleep 0.1; done # wait until slapd is terminated
+    [[ -f "$HOME/.ldaprc" ]] && rm -f $HOME/.ldaprc
+    echo "TLS_CERT ${LDAP_TLS_CRT_PATH}" > $HOME/.ldaprc
+    echo "TLS_KEY ${LDAP_TLS_KEY_PATH}" >> $HOME/.ldaprc
+    cp -f $HOME/.ldaprc ${CONTAINER_SERVICE_DIR}/slapd/assets/.ldaprc
+  fi
 
 
   #
   #
-  # remove config files
+  # remove container config files
   #
   #
   if [ "${LDAP_REMOVE_CONFIG_AFTER_SETUP,,}" == "true" ]; then
   if [ "${LDAP_REMOVE_CONFIG_AFTER_SETUP,,}" == "true" ]; then
     log-helper info "Remove config files..."
     log-helper info "Remove config files..."

+ 7 - 0
image/service/slapd/test.sh

@@ -0,0 +1,7 @@
+#!/bin/bash -e
+
+# Copy testing data to their respective directories on an as-needed basis
+mkdir -p /var/lib/ldap
+mkdir -p /etc/ldap/slapd.d
+cp -rf /container/test/database/* /var/lib/ldap/ || true
+cp -rf /container/test/config/* /etc/ldap/slapd.d/ || true

+ 1 - 5
test/test.bats

@@ -37,21 +37,17 @@ load test_helper
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.osixia.net -b dc=example,dc=org -ZZ -D "cn=admin,dc=example,dc=org" -w admin
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.osixia.net -b dc=example,dc=org -ZZ -D "cn=admin,dc=example,dc=org" -w admin
   clear_container
   clear_container
 
 
-  chmod 777 -R test/config/ test/database/ test/ssl/
-
   [ "$status" -eq 0 ]
   [ "$status" -eq 0 ]
 
 
 }
 }
 
 
 @test "ldapsearch existing database and config" {
 @test "ldapsearch existing database and config" {
 
 
-  run_image -h ldap.example.org -e LDAP_TLS=false -v $BATS_TEST_DIRNAME/database:/var/lib/ldap -v $BATS_TEST_DIRNAME/config:/etc/ldap/slapd.d
+  run_image -h ldap.example.org -e LDAP_TLS=false -v $BATS_TEST_DIRNAME/database:/container/test/database -v $BATS_TEST_DIRNAME/config:/container/test/config
   wait_process slapd
   wait_process slapd
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=osixia,dc=net -D "cn=admin,dc=osixia,dc=net" -w admin
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=osixia,dc=net -D "cn=admin,dc=osixia,dc=net" -w admin
   clear_container
   clear_container
 
 
-  chmod 777 -R test/config/ test/database/ test/ssl/
-
   [ "$status" -eq 0 ]
   [ "$status" -eq 0 ]
 
 
 }
 }

+ 1 - 1
test/test_helper.bash

@@ -9,7 +9,7 @@ build_image() {
 }
 }
 
 
 run_image() {
 run_image() {
-  CONTAINER_ID=$(docker run $@ -d $IMAGE_NAME)
+  CONTAINER_ID=$(docker run $@ -d $IMAGE_NAME --copy-service -c "/container/service/slapd/test.sh")
   CONTAINER_IP=$(get_container_ip_by_cid $CONTAINER_ID)
   CONTAINER_IP=$(get_container_ip_by_cid $CONTAINER_ID)
 }
 }