crystal-ldap v1.0.0

a Crystal lang LDAP client

LDAP Support for Crystal Lang

CI

Installation

Add the dependency to your shard.yml:

dependencies:
  ldap:
    github: spider-gazelle/crystal-ldap

Usage

Connecting and Binding

Passing a TLS context will upgrade the connection using start tls

require "ldap"

host = "ldap.forumsys.com"
port = 389
user = "cn=read-only-admin,dc=example,dc=com"
pass = "password"

# Standard LDAP port with unencrypted socket
socket = TCPSocket.new(host, port)

# Providing a context will upgrade to encrypted comms using start tls (official method)
tls = OpenSSL::SSL::Context::Client.new
tls.verify_mode = OpenSSL::SSL::VerifyMode::NONE

# Bind to the server
client = LDAP::Client.new(socket, tls)
client.authenticate(user, pass)

# Can now perform LDAP operations

To use the non-standard LDAPS (LDAP Secure, commonly known as LDAP over SSL) protocol then pass in a OpenSSL::SSL::Socket::Client directly: LDAP::Client.new(tls_socket)

# LDAPS method
socket = TCPSocket.new(host, port)
tls = OpenSSL::SSL::Context::Client.new
tls.verify_mode = OpenSSL::SSL::VerifyMode::NONE
socket = OpenSSL::SSL::Socket::Client.new(socket, context: tls, sync_close: true, hostname: host)

# Bind to the server
client = LDAP::Client.new(socket)
client.authenticate(user, pass)

# Can now perform LDAP operations

Querying

You can perform search requests


# You can use LDAP string filters directly
client.search(base: "dc=example,dc=com", filter: "(|(uid=einstein)(uid=training))")

# There are options to select particular attributes and limit response sizes
filter = LDAP::Request::Filter.equal("objectClass", "person")
client.search(
  base: "dc=example,dc=com",
  filter: filter,
  size: 6,
  attributes: ["hasSubordinates", "objectClass"]
)

# Filters can be combined using standard operations
filter = (
          LDAP::Request::Filter.equal("objectClass", "person") &
          LDAP::Request::Filter.equal("sn", "training")) |
          LDAP::Request::FilterParser.parse("(uid=einstein)"
         )
client.search(base: "dc=example,dc=com", filter: filter)

A search returns Array(LDAP::Entry). Each Entry exposes its dn separately from its attributes; attribute values are stored as raw Bytes (LDAP octet strings are not necessarily UTF-8):

entries = client.search(base: "dc=example,dc=com", filter: "(uid=einstein)")

entry = entries.first
entry.dn                  # => "uid=einstein,dc=example,dc=com"
entry["cn"]               # => ["Albert Einstein"]   (values decoded as String)
entry["mail"]?            # => ["einstein@ldap.forumsys.com"] or nil if absent
entry.bytes("objectGUID") # => Array(Bytes)          (raw, for binary attributes)
entry.keys                # => ["objectClass", "cn", "sn", "uid", "mail", ...]

A server-side size or time limit raises LDAP::Client::SearchLimitError, which carries the partial entries the server returned before stopping:

begin
  entries = client.search(base: "dc=example,dc=com")
rescue ex : LDAP::Client::SearchLimitError
  partial = ex.entries # incomplete, but usable
end
Repository

crystal-ldap

Owner
Statistic
  • 20
  • 3
  • 0
  • 1
  • 2
  • 4 days ago
  • May 7, 2020
License

MIT License

Links
Synced at

Thu, 16 Jul 2026 00:24:24 GMT

Languages