Go Ldap API is an HTTP API to an LDAP backend. Only supporting read at the moment, maybe one day it will break LDAP backends with ease and joy!
Go to file
2023-08-07 14:01:04 +02:00
.gitignore First commit 2022-10-08 18:52:11 +02:00
glapi.env.sample Update README 2023-08-07 14:01:04 +02:00
go.mod First commit 2022-10-08 18:52:11 +02:00
go.sum First commit 2022-10-08 18:52:11 +02:00
ldap.go v0.5.5: Add "ldap-auth-base-dn" parameter to search autenticating accounts, so we can separate authentication and manipulated base DN 2023-08-07 13:57:48 +02:00
LICENSE Initial commit 2022-10-05 19:25:56 +02:00
main.go v0.5.5: Add "ldap-auth-base-dn" parameter to search autenticating accounts, so we can separate authentication and manipulated base DN 2023-08-07 13:57:48 +02:00
README.md Update README 2023-08-07 14:01:04 +02:00

glapi

Go Ldap API is an HTTP API to an LDAP backend.
Only supporting read at the moment, maybe one day it will write, and break LDAP backends with ease and joy!
UPDATE: Yay, the day has come!

Usage

Start glapi with parameters on command line:

glapi -ldap-host ldap://ldap.example.org -ldap-base-dn dc=example,dc=org -ldap-user cn=yo,dc=example,dc=org -ldap-pass 'here_is_the_password'

or point it to a configuration file :

glapi -config glapi.env

Configuration file

LISTEN="0.0.0.0:8443"
LDAP_HOST="ldap://ldap.example.org"
# The base DN exposed to API. Could be buried in LDAP tree so we expose only a subset of directory.
LDAP_BASE_DN="dc=example,dc=org"

# This account search for valid user provided by authenticating client.
# Then glapi bind with client provided credentials to operate LDAP.
# Thus this account only needs bind privilege, and read access to users organizational unit        
LDAP_USER="cn=ldapreaduser,dc=example,dc=org"
LDAP_PASS='here_lies_the_password'

# This base DN is where we seach for authenticating accounts. This way we can chose not to expose them to the API.
LDAP_AUTH_BASE_DN="ou=users,dc=example,dc=org"

# Https support
HTTPS=true
SSL_CERTIFICATE=/etc/ssl/certs/server.pem
SSL_PRIVATE_KEY=/etc/ssl/private/server.key

Querying API

Search Entries

Search LDAP entries through the whole subtree, specifying organizationalUnit, commnName, objectClass, attribute to retrieve.
Each of these parameters can be replaced by "ALL" to act like a wildcard.

% curl -u admin:admin http://127.0.0.1:8080/ou=domains/yo/person | jq      
[
  {
    "DN": "cn=yo,dc=example.org,ou=domains,dc=example,dc=org",
    "Attributes": [
      {
        "Name": "sn",
        "Values": [
          "yo"
        ],
        "ByteValues": [
          "eW8="
        ]
      },
      {
        "Name": "cn",
        "Values": [
          "yo"
        ],
        "ByteValues": [
          "eW8="
        ]
      },
      {
        "Name": "objectClass",
        "Values": [
          "inetOrgPerson",
          "organizationalPerson",
          "person",
          "top",
          "inetLocalMailRecipient"
        ],
        "ByteValues": [
          "aW5ldE9yZ1BlcnNvbg==",
          "b3JnYW5pemF0aW9uYWxQZXJzb24=",
          "cGVyc29u",
          "dG9w",
          "aW5ldExvY2FsTWFpbFJlY2lwaWVudA=="
        ]
      },
      {
        "Name": "mail",
        "Values": [
          "yo@example.org"
        ],
        "ByteValues": [
          "eW9AcGxvcGl0by50aw=="
        ]
      },
      {
        "Name": "mailLocalAddress",
        "Values": [
          "root@example.org",
          "postmaster@example.org",
        ],
        "ByteValues": [
          "cm9vdEBleGFtcGxlLm9yZw==",
          "cG9zdG1hc3RlckBleGFtcGxlLm9yZw==",
        ]
      },
      {
        "Name": "uid",
        "Values": [
          "yo"
        ],
        "ByteValues": [
          "eW8="
        ]
      }
    ]
  }
]

Using wildcards everywhere and ldif format, you can get a dump of ldap:

% curl -u admin:admin "http://127.0.0.1:8080/ALL/ALL/ALL?format=ldif"
dn: dc=example,dc=org
objectClass: organization
objectClass: top
objectClass: dcObject
dc: example
o: example.org

dn: cn=admin,dc=example,dc=org
objectClass: organizationalRole
objectClass: top
objectClass: simpleSecurityObject
cn: admin

dn: cn=yo,dc=example,dc=org
objectClass: organizationalRole
objectClass: top
objectClass: simpleSecurityObject
cn: yo
userPassword: {SSHA}edited

[...]

Add operational attributes with "*,+":

% curl -u admin:admin "http://127.0.0.1:8080/ALL/ALL/ALL/*,+?format=ldif"   
dn: dc=example,dc=org
objectClass: organization
objectClass: top
objectClass: dcObject
dc: example
o: example.org
structuralObjectClass: organization
entryUUID: af93fd38-3139-103a-8d41-05c00494facf
creatorsName: cn=admin,dc=example,dc=org
createTimestamp: 20200523120715Z
entryCSN: 20200523120715.282611Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=org
modifyTimestamp: 20200523120715Z
entryDN: dc=example,dc=org
subschemaSubentry: cn=Subschema
hasSubordinates: TRUE

dn: cn=admin,dc=example,dc=org
objectClass: organizationalRole
objectClass: top
objectClass: simpleSecurityObject
cn: admin
structuralObjectClass: organizationalRole
entryUUID: af9a1556-3139-103a-8d42-05c00494facf
creatorsName: cn=admin,dc=example,dc=org
createTimestamp: 20200523120715Z
entryCSN: 20200523120715.322559Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=org
modifyTimestamp: 20200523120715Z
entryDN: cn=admin,dc=example,dc=org
subschemaSubentry: cn=Subschema
hasSubordinates: FALSE

[...]

Output format

Default output is in json. The following formats are supported:

  • json (default)
  • text (ini style)
  • ldif
  • textvalue (only attribute values are returned)
  • textvalue-nodn (only attribute values, no dn, no linefeed between entries. Made for Rspamd multimap module)

Specify with "format" query parameter:

% curl -u admin:admin "http://127.0.0.1:8080/ou=domains/yo/person?format=text"
dn=cn=yo,dc=example.org,ou=domains,dc=example,dc=org
sn=yo
cn=yo
objectClass=inetOrgPerson
objectClass=organizationalPerson
objectClass=person
objectClass=top
objectClass=inetLocalMailRecipient
mail=yo@example.org
mailLocalAddress=root@example.org
mailLocalAddress=postmaster@example.org
uid=yo

% curl -u admin:admin "http://127.0.0.1:8080/ou=domains/yo/person?format=ldif"
dn: cn=yo,dc=example.org,ou=domains,dc=example,dc=org
sn: yo
cn: yo
objectClass: inetOrgPerson
objectClass: organizationalPerson
objectClass: person
objectClass: top
objectClass: inetLocalMailRecipient
mail: yo@example.org
mailLocalAddress: root@example.org
mailLocalAddress=postmaster@example.org
uid: yo

Select attributes to get

You can select attributes to get by adding them in 4th position :

% curl -u admin:admin "http://127.0.0.1:8080/ou=domains/yo/person/mail?format=textvalue"
cn=yo,dc=example.org,ou=domains,dc=example,dc=org
yo@example.org

% curl -u admin:admin "http://127.0.0.1:8080/ou=domains/yo/person/mail?format=textvalue-nodn"
yo@example.org

Create entries

Create a new OU =users", then a new user :

% curl -u "admin:admin" --header "Content-Type: application/json" -X POST 
--data '{"objectClass":["organizationalUnit","top"],"ou":"users"' \
https://127.0.0.1:8443/ou=users,dc=example,dc=org

% curl -u "admin:admin" --header "Content-Type: application/json" -X POST 
--data '{"objectClass":["person","top"],"cn":"newuser","sn":"New"}' \
https://127.0.0.1:8443/cn=newuser,ou=users,dc=example,dc=org

### Modify entries
Add a description to the new account:

% curl -u "admin:admin" --header "Content-Type: application/json" -X PUT 
--data '{"objectClass":["person","top"],"cn":"newuser","sn":"New","description":"Test account"}' \
https://127.0.0.1:8443/cn=newuser,ou=users,dc=example,dc=org

Missing attributes will be removed from entry.

Delete entries

Remove newuser :

% curl -u "admin:admin" -X DELETE \
https://127.0.0.1:8443/cn=newuser,ou=users,dc=example,dc=org