simple-ldap
simple LDAP server exposing user accounts defined in local JSON file
License
MIT
About
This package implements LDAP server suitable for authentication. The supported user base is defined in a local JSON file read once on start. Name of JSON file is provided in first argument provided on starting service, in environment variable SIMPLE_LDAP_DB_FILE
or in file ./ldap-db.json
.
Data Format
The simulated LDAP tree is flat, fixed and simple by design. All entries are children of root DN o=foo
with foo
being customizable via environment variable SIMPLE_LDAP_ORGANIZATION
.
The JSON read from file must be an array of objects each describing another LDAP entry eventually subordinated to o=foo
. Either object's properties are describing attributes of resulting entry. A property named cn
must be provided and is used to generate entry's DN:
cn=<value of property cn>,o=foo
This DN is meant to uniquely select the entry in resulting LDAP tree. Thus, it is hashed to create the entry's unique ID exposed in attribute entryUUID
. You shouldn't change the cn
of an entry to keep its DN as well as its entryUUID
unchanged for either one might be used for associating data with the related entry.
All properties are basically adopted as attributes. However, by adding a period and the name of a hashing algorithm to a property's name the provided value is hashed and assigned to resulting attribute instead.
Example
[
{
"cn": "John Doe",
"sn": "Doe",
"givenName": "John",
"userPassword.ssha": "secret",
"customPIN.ssha256": "12345"
}
]
This JSON input results in the following LDAP entry:
dn: cn=John Doe,o=foo
objectclass: top
objectclass: inetorgperson
cn: John Doe
givenName: John
sn: Doe
userPassword: {SSHA}tG0H2qnuiLBSb/Z085nHKxaiDYHUk/x1xAtaYueyb4DQ/LPF
customPIN: {SSHA256}yvWoHbrHR5Q4TWUf1JwHPlYTm6X7qtM8uENOqxreZiVWUinR0iarp93rtWkecX1R
entryUUID: c5de1dca-a879-29df-83db-1552edcfb6fb
The values of userPassword
and customPIN
are salted hashes of values provided in JSON. In either case a random salt has been applied.
Querying
The LDAP server works with commonly available clients.
/ # ldapsearch -x -H ldap://host.docker.internal -b o=foo
# extended LDIF
#
# LDAPv3
# base <o=foo> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# foo
dn: o=foo
o: foo
objectclass: organization
objectclass: top
# John Doe, foo
dn: cn=John Doe,o=foo
objectclass: top
objectclass: inetorgperson
cn: John Doe
sn: Doe
givenName: John
userPassword:: e1NTSEF9dEcwSDJxbnVpTEJTYi9aMDg1bkhLeGFpRFlIVWsveDF4QXRhWXVleWI
0RFEvTFBG
customPIN: {SSHA256}yvWoHbrHR5Q4TWUf1JwHPlYTm6X7qtM8uENOqxreZiVWUinR0iarp
93rtWkecX1R
entryUUID: c5de1dca-a879-29df-83db-1552edcfb6fb
# search result
search: 2
result: 0 Success
# numResponses: 3
# numEntries: 2
This example is querying all entries in thread o=foo
. Filters are mostly obeyed:
~ > ldapsearch -LLL -x -H ldap://host.docker.internal -b o=foo "(sn=Doe)"
dn: cn=John Doe,o=foo
objectclass: top
objectclass: inetorgperson
cn: John Doe
sn: Doe
givenName: John
userPassword:: e1NTSEF9dEcwSDJxbnVpTEJTYi9aMDg1bkhLeGFpRFlIVWsveDF4QXRhWXVleWI
0RFEvTFBG
inpasCustomPIN: {SSHA256}yvWoHbrHR5Q4TWUf1JwHPlYTm6X7qtM8uENOqxreZiVWUinR0iarp
93rtWkecX1R
entryUUID: c5de1dca-a879-29df-83db-1552edcfb6fb
Using a more specific base DN is supported, too:
~ > ldapsearch -LLL -x -H ldap://host.docker.internal -b "cn=John Doe,o=foo"
dn: cn=John Doe,o=foo
objectclass: top
objectclass: inetorgperson
cn: John Doe
sn: Doe
givenName: John
userPassword:: e1NTSEF9dEcwSDJxbnVpTEJTYi9aMDg1bkhLeGFpRFlIVWsveDF4QXRhWXVleWI
0RFEvTFBG
inpasCustomPIN: {SSHA256}yvWoHbrHR5Q4TWUf1JwHPlYTm6X7qtM8uENOqxreZiVWUinR0iarp
93rtWkecX1R
entryUUID: c5de1dca-a879-29df-83db-1552edcfb6fb
Limitations
Currently, the LDAP server is handling unencrypted traffic on port 389, only. There is support for search queries, only. You can't actually bind against this service. In addition, it is always exposing every attribute per entry. So contrary to common behaviour of existing LDAP servers hashed passwords are provided in response to public queries, too.
Use Cases
Limitations listed above render this service inappropriate for public production environments. You should use it for testing purposes or in a stack or pod of containers that communicate over encrypted connections, only.
Usage
This package is deployed as a docker image:
docker run -v $HOME/config:/config:ro -p 389:389 \
registry.gitlab.com/cepharum-foss/simple-ldap
On start, it is looking for a file named ldap-db.json, simple-ldap-entries.json or entries.json in folder /config which is addressing bound host folder here. First existing file is used. Service is exposed on port 389.
In context of Docker Swarm you can use a docker secret named simple-ldap.config.tgz for easy distribution of data. This secret must contain a compressed tar archive. It is extracted into folder /config at start of container.