Contents

perfectlysoft/perfect-ldap

This project provides an express OpenLDAP class wrapper which enable access to OpenLDAP servers and Windows Active Directory server.

Quick Start

Add the following dependency to your project's Package.swift file:

.package(url: "https://github.com/PerfectlySoft/Perfect-LDAP.git", 
from: "3.0.0")

// in the target section:
depedencies: ["PerfectLDAP"]

Then import PerfectLDAP to your source code:


import PerfectLDAP

Connect to LDAP Server

You can create actual connections as need with or without login credential. The full API is LDAP(url:String, loginData: Login?, codePage: Iconv.CodePage). The codePage option is for those servers applying character set other than .UTF8, e.g., set codePage: .GB2312 to connect to LDAP server in Simplified Chinese.

TLS Option

PerfectLDAP provides TLS options for network security considerations, i.e, you can choose either ldap:// or ldaps:// for connections, as demo below:

// this will connect to a 389 port without any encryption
let ld = try LDAP(url: "ldap://perfect.com")

or,

// this will connect to a 636 port with certificates
let ld = try LDAP(url: "ldaps://perfect.com")

Connection Timeout

Once connected, LDAP object could be set with timeout option, and the timing unit is second:

// set the timeout for communication. In this example, connection will be timeout in ten seconds.
connection.timeout = 10

Login or Anonymous

Many servers mandate login before performing any actual LDAP operations, however, PerfectLDAP provides multiple login options as demo below:

// this snippet demonstrate how to connect to LDAP server with a login credential
// NOTE: this kind of connection will block the thread until server return or timeout.
// create login credential
let credential = LDAP.login( ... )
let connection = try LDAP(url: "ldaps://...", loginData: login)

Aside the above synchronous login option, a two phased threading login process could also bring more controls to the application:

// first create a connection
let connection = try LDAP(url: "ldaps:// ...")

// setup login info
let credential = LDAP.login( ... )

// login in a separated thread
connection.login(info: credential) { err in
  // if err is not nil, then something must be wrong in the login process.
}

Login Options

PerfectLDAP provides a special object called LDAP.Login to store essential account information for LDAP connections and the form of constructor is subject to the authentication types:

Simple Login

To use simple login method, simply call LDAP.login(binddn: String, password: String), as snippet below:

let credential = LDAP.Login(binddn: "CN=judy,CN=Users,DC=perfect,DC=com", password: "0penLDAP")

GSSAPI

To apply GSSAPI authentication, call LDAP.login(user:String, mechanism: AuthType) to construct a login credential (assuming the user has already acquired a valid ticket):

// this call will generate a GSSAPI login credential
let credential = LDAP.login(user: "judy", mechanism: .GSSAPI)

GSS-SPNEGO and Digest-MD5 (⚠️EXPERIMENTAL⚠️)

To apply other SASL mechanisms, such as GSS-SPNEGO and Digest-MD5 interactive logins, call LDAP.login(authname: String, user: String, password: String, realm: String, mechanism: AuthType) as demo below:

// apply DIGEST-MD5 mechanism.
let credential = LDAP.Login(authname: "judy", user: "DN:CN=judy,CN=Users,DC=perfect,DC=com", password: "0penLDAP", realm: "PERFECT.COM", mechanism: .DIGEST)

⚠️NOTE⚠️ The authname is equivalent to SASL_CB_AUTHNAME and user is actually the macro of SASL_CB_USER. If any parameter above is not applicable to your case, simply assign an empty string "" to ignore it.

Attribute Operations

PerfectLDAP provides add() / modify() and delete() for attributes operations with both synchronous and asynchronous options.

Add Attributes (⚠️EXPERIMENTAL⚠️)

Function LDAP.add() can add attributes to a specific DN with parameters below:

  • distinguishedName: String, specific DN
  • attributes:[String:[String]], attributes as an dictionary to add. In this dictionary, every attribute, as a unique key in the dictionary, could have a series of values as an array.

Both asynchronous add() and synchronous add() share the same parameters above, take example:

// try an add() synchronously.
do {
  try connection.add(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com", attributes: ["mail":["judy@perfect.com", "judy@perfect.org"]])
}catch (let err) {
    // failed for some reason
}

// try and add() asynchronously:
connection.add(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com", attributes: ["mail":["judy@perfect.com", "judy@perfect.org"]]) { err in
  // if nothing wrong, err will be nil
}

Modify Attributes

Function LDAP.modify() can modify attributes from a specific DN with parameters below:

  • distinguishedName: String, specific DN
  • attributes:[String:[String]], attributes as an dictionary to modify. In this dictionary, every attribute, as a unique key in the dictionary, could have a series of values as an array.
  • method: specify if an attribute should be added, removed or replaced (default)

- add: LDAP_MOD_ADD | LDAP_MOD_BVALUES - remove: LDAP_MOD_DELETE | LDAP_MOD_BVALUES - replace: LDAP_MOD_REPLACE | LDAP_MOD_BVALUES

Both asynchronous modify() and synchronous modify() share the same parameters above, take example:

// try and modify() synchronously.
do {
  try connection.modify(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com", attributes: ["codePage":["437"]])
}catch (let err) {
    // failed for some reason
}

// try and modify() asynchronously:
connection.modify(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com", attributes:["codePage":["437"]]) { err in
  // if nothing wrong, err will be nil
}

Example: Add and remove user from group

// add user to group
do {
  try connection.modify(distinguishedName: "CN=employee_group,CN=Group,DC=perfect,DC=com", attributes: ["member":["CN=judy,CN=User,DC=perfect,DC=com"]], method: LDAP_MOD_ADD | LDAP_MOD_BVALUES)
}catch (let err) {
    // failed for some reason
}

// remove user from group
do {
  try connection.modify(distinguishedName: "CN=employee_group,CN=Group,DC=perfect,DC=com", attributes: ["member":["CN=judy,CN=User,DC=perfect,DC=com"]], method: LDAP_MOD_DELETE | LDAP_MOD_BVALUES)
}catch (let err) {
    // failed for some reason
}

Delete Attributes (⚠️EXPERIMENTAL⚠️)

Function LDAP.delete() can delete attributes from a specific DN with only one parameter:

  • distinguishedName: String, specific DN

Both asynchronous delete() and synchronous delete() share the same parameter above, take example:

// try an delete() synchronously.
do {
  try connection.delete(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com")
}catch (let err) {
    // failed for some reason
}

// try and delete() asynchronously:
connection.delete(distinguishedName: "CN=judy,CN=User,DC=perfect,DC=com") { err in
  // if nothing wrong, err will be nil
}

Further Information

For more information on the Perfect project, please visit perfect.org.

Package Metadata

Repository: perfectlysoft/perfect-ldap

Default branch: master

README: README.md