ExOpenDirectory
Elixir bindings to macOS OpenDirectory.framework for directory services.
Provides native access to local accounts, LDAP servers, and Active Directory
domains via Apple's opendirectoryd daemon. Uses Rustler
NIFs backed by objc2-open-directory.
Why Not Just Use :eldap?
OpenDirectory provides capabilities that raw LDAP cannot:
- AD integration — Apple's own AD plugin handles site-aware DC discovery, Kerberos ticket acquisition, nested group resolution, and GPO awareness
- Local directory — Query local macOS users/groups, not just networked ones
- Password policy — Reads
msDS-UserPasswordExpiryTimeComputedand local password policy, computing days-until-expiry correctly - Authentication —
ODRecord.verifyPasswordtriggers the full auth chain (Kerberos on AD-bound nodes) rather than a simple LDAP bind
If you're building a NoMAD/Jamf Connect replacement, you need this framework.
If you just need basic LDAP queries, :eldap or exldap may suffice.
Installation
def deps do
[{:ex_open_directory, "~> 0.1.0"}]
end
Requires Rust toolchain (rustup). macOS only.
Usage
# Connect to the search node (searches all configured directories)
{:ok, node} = ExOpenDirectory.connect(:search)
# Find a user
{:ok, record} = ExOpenDirectory.find_user(node, "jsmith")
# Get attributes
{:ok, attrs} = ExOpenDirectory.get_attributes(record, [
"dsAttrTypeStandard:RealName",
"dsAttrTypeStandard:EMailAddress"
])
# Check group membership (handles AD nested groups)
true = ExOpenDirectory.member?(node, "jsmith", "Engineering")
# Authenticate (triggers Kerberos on AD-bound nodes)
:ok = ExOpenDirectory.authenticate(node, "jsmith", "password123")
# Check password expiry
{:ok, policy} = ExOpenDirectory.password_policy(node, "jsmith")
policy.days_until_expiry #=> 14License
MIT